using Admin.NET.Core.Service;
using Microsoft.AspNetCore.Http;
using Furion.DatabaseAccessor;
using Furion.FriendlyException;
using Mapster;
using SqlSugar;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Admin.NET.Application.Entity;
using System.Text.Json;
using System.Text;
using System.Net.Http.Headers;
using Microsoft.Extensions.Configuration;
using System.Text.Json.Serialization;

namespace Admin.NET.Application.Service.CustomerService;

/// <summary>
/// RAG智能客服服务
/// </summary>
[ApiDescriptionSettings(Order = 370)]
public partial class CustomerServiceService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<CustomerServiceMessage> _messageRepo;
    private readonly SqlSugarRepository<WorkOrder> _workOrderRepo;
    private readonly SqlSugarRepository<Admin.NET.Application.Entity.KnowledgeBase> _knowledgeRepo;
    private readonly SqlSugarRepository<Admin.NET.Application.Entity.KnowledgeVector> _vectorRepo;
    private readonly SqlSugarRepository<Syssalesorder> _salesOrderRepo;
    private readonly SqlSugarRepository<Syspurchaseorder> _purchaseOrderRepo;
    private readonly SqlSugarRepository<Sysinstockorder> _instockOrderRepo;
    private readonly SqlSugarRepository<Sysoutstockorder> _outstockOrderRepo;
    private readonly IConfiguration _configuration;

    public CustomerServiceService(
        SqlSugarRepository<CustomerServiceMessage> messageRepo,
        SqlSugarRepository<WorkOrder> workOrderRepo,
        SqlSugarRepository<Admin.NET.Application.Entity.KnowledgeBase> knowledgeRepo,
        SqlSugarRepository<Admin.NET.Application.Entity.KnowledgeVector> vectorRepo,
        SqlSugarRepository<Syssalesorder> salesOrderRepo,
        SqlSugarRepository<Syspurchaseorder> purchaseOrderRepo,
        SqlSugarRepository<Sysinstockorder> instockOrderRepo,
        SqlSugarRepository<Sysoutstockorder> outstockOrderRepo,
        IConfiguration configuration)
    {
        _messageRepo = messageRepo;
        _workOrderRepo = workOrderRepo;
        _knowledgeRepo = knowledgeRepo;
        _vectorRepo = vectorRepo;
        _salesOrderRepo = salesOrderRepo;
        _purchaseOrderRepo = purchaseOrderRepo;
        _instockOrderRepo = instockOrderRepo;
        _outstockOrderRepo = outstockOrderRepo;
        _configuration = configuration;
        
        // 异步初始化示例知识库数据
        _ = Task.Run(async () => await InitializeSampleKnowledge());
    }

    /// <summary>
    /// 发送消息给RAG智能客服
    /// </summary>
    [DisplayName("发送消息给RAG智能客服")]
    public async Task<CustomerServiceResponse> SendMessage(CustomerServiceRequest input)
    {
        try
        {
            Console.WriteLine($"收到用户消息: {input.Message}");
            
            // 保存用户消息
            var userMessage = new CustomerServiceMessage
            {
                UserId = input.UserId,
                UserName = input.UserName,
                Message = input.Message,
                MessageType = "text",
                Timestamp = DateTime.Now,
                IsFromUser = true,
                ConversationId = input.ConversationId
            };
            
            // 添加数据库操作重试机制
            await RetryDatabaseOperation(async () => await _messageRepo.InsertAsync(userMessage));
            Console.WriteLine("用户消息已保存到数据库");
            
            // 将用户消息写入个人记忆（向量数据库）——改为同步等待，避免并发复用同一连接
            try
            {
                if (_configuration.GetValue<bool>("RAGSettings:EnablePersonalMemory", true))
                {
                    await UpsertPersonalMemoryAsync(input.UserId, input.ConversationId, true, input.Message);
                }
            }
            catch { }

            // 使用RAG处理消息
            var response = await ProcessWithRAG(input);
            Console.WriteLine($"RAG回复: {response.Message}");

            // 保存AI回复
            var agentMessage = new CustomerServiceMessage
            {
                UserId = 0,
                UserName = "小智",
                Message = response.Message,
                MessageType = "text",
                Timestamp = DateTime.Now,
                IsFromUser = false,
                ConversationId = input.ConversationId,
                Actions = response.Actions?.ToJson()
            };
            
            // 添加数据库操作重试机制
            await RetryDatabaseOperation(async () => await _messageRepo.InsertAsync(agentMessage));
            Console.WriteLine("AI回复已保存到数据库");

            // 将AI回复写入个人记忆（向量数据库）——改为同步等待，避免并发复用同一连接
            try
            {
                if (_configuration.GetValue<bool>("RAGSettings:EnablePersonalMemory", true))
                {
                    await UpsertPersonalMemoryAsync(input.UserId, input.ConversationId, false, response.Message);
                }
            }
            catch { }

            return response;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"处理消息失败: {ex.Message}");
            Console.WriteLine($"详细错误: {ex}");
            
            // 如果数据库操作失败，仍然返回RAG回复
            try
            {
                var response = await ProcessWithRAG(input);
                Console.WriteLine($"RAG回复（无数据库保存）: {response.Message}");
                return response;
            }
            catch (Exception ragEx)
            {
                Console.WriteLine($"RAG处理也失败: {ragEx.Message}");
                return new CustomerServiceResponse
                {
                    Message = "抱歉，服务暂时不可用，请稍后重试或转接人工客服。",
                    MessageType = "text",
                    ConversationId = input.ConversationId,
                    TransferToHuman = true
                };
            }
        }
    }

    /// <summary>
    /// 数据库操作重试机制
    /// </summary>
    private async Task RetryDatabaseOperation(Func<Task> operation, int maxRetries = 3)
    {
        for (int i = 0; i < maxRetries; i++)
        {
            try
            {
                await operation();
                return;
            }
            catch (Exception ex) when (i < maxRetries - 1)
            {
                Console.WriteLine($"数据库操作失败，第 {i + 1} 次重试: {ex.Message}");
                Console.WriteLine($"错误类型: {ex.GetType().Name}");
                if (ex.InnerException != null)
                {
                    Console.WriteLine($"内部错误: {ex.InnerException.Message}");
                }
                await Task.Delay(1000 * (i + 1)); // 递增延迟
            }
            catch (Exception ex)
            {
                Console.WriteLine($"数据库操作最终失败: {ex.Message}");
                Console.WriteLine($"完整错误信息: {ex}");
                throw;
            }
        }
    }

    /// <summary>
    /// 直接使用RAGFLOW处理用户消息，不进行知识检索
    /// </summary>
    private async Task<CustomerServiceResponse> ProcessWithRAG(CustomerServiceRequest input)
    {
        try
        {
            // 检查是否使用RAGFlow
            var useRAGFlow = _configuration.GetValue<bool>("RAGSettings:UseRAGFlow", false);
            Console.WriteLine($"UseRAGFlow配置值: {useRAGFlow}");
            
            string response;
            if (useRAGFlow)
            {
                Console.WriteLine("直接使用RAGflow生成回复，不进行知识检索");
                // 直接调用RAGFLOW，不进行任何知识检索或上下文构建
                response = await GenerateRAGFlowResponseDirect(input.Message, input.UserId, input.ConversationId);
            }
            else
            {
                Console.WriteLine("使用本地数据分析生成回复");
                // 使用数据分析生成智能回复
                var intent = await RecognizeIntent(input.Message);
                var dataAnalysis = await QueryDatabaseAndAnalyze(input.Message, intent);
                
                // 根据意图类型生成不同的回复
                switch (intent.Type)
                {
                    case "inventory_query":
                        response = await GenerateInventoryResponseWithData(input.Message, "", dataAnalysis);
                        break;
                    case "sales_order_query":
                        response = await GenerateOrderResponseWithData(input.Message, "", dataAnalysis);
                        break;
                    case "customer_query":
                        response = await GenerateCustomerResponseWithData(input.Message, "", dataAnalysis);
                        break;
                    case "warehouse_query":
                        response = await GenerateWarehouseResponseWithData(input.Message, "", dataAnalysis);
                        break;
                    case "system_help":
                        response = await GenerateHelpResponseWithData(input.Message, "", dataAnalysis);
                        break;
                    case "error_report":
                        response = await GenerateErrorResponseWithData(input.Message, "", dataAnalysis);
                        break;
                    default:
                        response = await GenerateGeneralResponseWithData(input.Message, "", dataAnalysis);
                        break;
                }
            }
            
            Console.WriteLine($"生成的回复内容: {response}");
            
            return new CustomerServiceResponse
            {
                Message = response,
                MessageType = "text",
                Actions = new List<CustomerServiceAction>(),
                ConversationId = input.ConversationId,
                WorkOrderCreated = false,
                TransferToHuman = false
            };
        }
        catch (Exception ex)
        {
            Console.WriteLine($"RAG智能客服处理失败: {ex.Message}");
            return new CustomerServiceResponse
            {
                Message = "抱歉，服务暂时不可用，请稍后再试或转接人工客服。",
                MessageType = "text",
                ConversationId = input.ConversationId,
                TransferToHuman = true
            };
        }
    }

    /// <summary>
    /// 意图识别
    /// </summary>
    private async Task<UserIntent> RecognizeIntent(string userMessage)
    {
        await Task.CompletedTask; // 避免async警告
        
        var intentKeywords = new Dictionary<string, string[]>
        {
            ["inventory_query"] = new[] { "库存", "查询", "数量", "剩余", "SKU", "商品" },
            ["order_query"] = new[] { "订单", "状态", "进度", "单号", "查询订单" },
            ["warehouse_operation"] = new[] { "入库", "出库", "调拨", "盘点", "仓库操作" },
            ["system_help"] = new[] { "帮助", "怎么", "如何", "操作", "步骤" },
            ["error_report"] = new[] { "错误", "故障", "问题", "异常", "无法", "不能" },
            ["work_order"] = new[] { "工单", "技术支持", "客服", "人工" }
        };

        var message = userMessage.ToLower();
        foreach (var kvp in intentKeywords)
        {
            if (kvp.Value.Any(keyword => message.Contains(keyword)))
            {
                return new UserIntent
                {
                    Type = kvp.Key,
                    Confidence = 0.8f,
                    Entities = ExtractEntities(userMessage, kvp.Key)
                };
            }
        }

        return new UserIntent
        {
            Type = "general_query",
            Confidence = 0.5f,
            Entities = new Dictionary<string, string>()
        };
    }

    /// <summary>
    /// 知识检索（恢复数据库功能）
    /// </summary>
    private async Task<List<Admin.NET.Application.Entity.KnowledgeBase>> RetrieveKnowledge(string query, UserIntent intent)
    {
        try
        {
            var allResults = new List<Admin.NET.Application.Entity.KnowledgeBase>();

            // 1. 基于意图的精确匹配
            var intentResults = await _knowledgeRepo.GetListAsync(k => 
                k.Category == intent.Type || 
                k.Keywords.Contains(intent.Type));
            allResults.AddRange(intentResults);

            // 2. 关键词匹配
            var keywords = ExtractKeywords(query);
            foreach (var keyword in keywords)
            {
                var keywordResults = await _knowledgeRepo.GetListAsync(k => 
                    k.Title.Contains(keyword) || 
                    k.Content.Contains(keyword) || 
                    k.Keywords.Contains(keyword));
                allResults.AddRange(keywordResults);
            }

            // 3. 向量相似度检索（如果启用）
            if (_configuration["RAGSettings:EnableVectorSearch"] == "true")
            {
                var vectorResults = await RetrieveByVectorSimilarity(query);
                allResults.AddRange(vectorResults);
            }

            // 4. 去重、排序和限制结果
            var uniqueResults = allResults
                .GroupBy(k => k.Id)
                .Select(g => g.First())
                .OrderByDescending(k => CalculateRelevanceScore(k, query, intent))
                .Take(5)
                .ToList();

            Console.WriteLine($"从数据库检索到 {uniqueResults.Count} 条知识");
            return uniqueResults;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"数据库知识检索失败: {ex.Message}");
            
            // 如果数据库检索失败，使用内置知识库
            return await GetBuiltInKnowledge(query, intent);
        }
    }

    /// <summary>
    /// 获取内置知识库（备用方案）
    /// </summary>
    private async Task<List<Admin.NET.Application.Entity.KnowledgeBase>> GetBuiltInKnowledge(string query, UserIntent intent)
    {
        await Task.CompletedTask; // 避免async警告
        
        Console.WriteLine("使用内置知识库作为备用方案");
        
        // 返回内置知识库数据
        var builtInKnowledge = new List<Admin.NET.Application.Entity.KnowledgeBase>
        {
            new Admin.NET.Application.Entity.KnowledgeBase
            {
                Id = 1,
                Title = "WMS库存管理基础",
                Category = "inventory_query",
                Keywords = "库存,管理,查询,SKU,商品",
                Content = "WMS库存管理是仓库管理系统的核心功能。主要包含：1. 实时库存查询 - 支持按SKU、商品名称、仓库位置查询；2. 库存预警 - 当库存低于安全库存时自动提醒；3. 库存盘点 - 定期进行库存盘点确保数据准确性；4. 库存调拨 - 支持仓库间库存调拨操作。",
                Source = "系统内置",
                DocumentType = "text",
                Priority = 1,
                IsEnabled = true,
                CreateTime = DateTime.Now,
                UpdateTime = DateTime.Now
            },
            new Admin.NET.Application.Entity.KnowledgeBase
            {
                Id = 2,
                Title = "订单状态查询指南",
                Category = "order_query",
                Keywords = "订单,状态,查询,进度,单号",
                Content = "订单状态查询功能说明：1. 销售订单状态包括：草稿、待审核、已审核、未出库、已完成、已关闭；2. 采购订单状态包括：草稿、待审核、已审核、未入库、已完成、已关闭；3. 查询方式：支持按订单号、客户名称、时间范围查询；4. 订单进度跟踪：可查看订单的详细处理进度和预计完成时间。",
                Source = "系统内置",
                DocumentType = "text",
                Priority = 1,
                IsEnabled = true,
                CreateTime = DateTime.Now,
                UpdateTime = DateTime.Now
            },
            new Admin.NET.Application.Entity.KnowledgeBase
            {
                Id = 3,
                Title = "仓库操作流程",
                Category = "warehouse_operation",
                Keywords = "仓库,操作,入库,出库,调拨,盘点",
                Content = "仓库操作标准流程：1. 入库操作：接收货物→验货→入库登记→更新库存；2. 出库操作：订单确认→拣货→验货→出库登记→更新库存；3. 调拨操作：申请调拨→审核→执行调拨→更新双方库存；4. 盘点操作：制定盘点计划→执行盘点→差异分析→库存调整。",
                Source = "系统内置",
                DocumentType = "text",
                Priority = 1,
                IsEnabled = true,
                CreateTime = DateTime.Now,
                UpdateTime = DateTime.Now
            }
        };

        // 根据意图和关键词过滤
        var relevantKnowledge = builtInKnowledge.Where(k => 
            k.Category == intent.Type || 
            k.Keywords.Contains(query) ||
            k.Title.Contains(query) ||
            k.Content.Contains(query)
        ).ToList();

        return relevantKnowledge.Take(3).ToList();
    }

    /// <summary>
    /// 提取查询关键词
    /// </summary>
    private List<string> ExtractKeywords(string query)
    {
        var keywords = new List<string>();
        
        // WMS相关关键词
        var wmsKeywords = new[] { "库存", "订单", "仓库", "入库", "出库", "调拨", "盘点", "客户", "供应商", "商品", "SKU" };
        
        foreach (var keyword in wmsKeywords)
        {
            if (query.Contains(keyword))
            {
                keywords.Add(keyword);
            }
        }

        // 提取可能的SKU或订单号
        var skuMatch = System.Text.RegularExpressions.Regex.Match(query, @"[A-Za-z0-9\-_]{3,}");
        if (skuMatch.Success)
        {
            keywords.Add(skuMatch.Value);
        }

        return keywords;
    }

    /// <summary>
    /// 向量相似度检索
    /// </summary>
    private async Task<List<Admin.NET.Application.Entity.KnowledgeBase>> RetrieveByVectorSimilarity(string query)
    {
        try
        {
            // 生成查询向量
            var queryVector = await GenerateEmbedding(query);
            
            // 计算相似度并检索
            var similarVectors = await _vectorRepo.GetListAsync();
            var results = new List<Admin.NET.Application.Entity.KnowledgeBase>();
            
            foreach (var vector in similarVectors)
            {
                var similarity = CalculateCosineSimilarity(queryVector, vector.Vector);
                if (similarity > 0.7) // 相似度阈值
                {
                    var knowledge = await _knowledgeRepo.GetByIdAsync(vector.KnowledgeId);
                    if (knowledge != null)
                    {
                        results.Add(knowledge);
                    }
                }
            }
            
            return results.OrderByDescending(k => k.Id).Take(3).ToList();
        }
        catch
        {
            return new List<Admin.NET.Application.Entity.KnowledgeBase>();
        }
    }

    /// <summary>
    /// 生成文本嵌入向量
    /// </summary>
    private async Task<float[]> GenerateEmbedding(string text)
    {
        await Task.CompletedTask; // 避免async警告
        
        // 这里可以集成OpenAI Embeddings API或其他嵌入模型
        // 简化实现：使用文本哈希作为向量
        var hash = text.GetHashCode();
        var vector = new float[384]; // 假设使用384维向量
        var random = new Random(hash);
        
        for (int i = 0; i < vector.Length; i++)
        {
            vector[i] = (float)(random.NextDouble() * 2 - 1);
        }
        
        return vector;
    }

    /// <summary>
    /// 计算余弦相似度
    /// </summary>
    private float CalculateCosineSimilarity(float[] vectorA, string vectorBJson)
    {
        try
        {
            var vectorB = JsonSerializer.Deserialize<float[]>(vectorBJson);
            if (vectorA.Length != vectorB.Length) return 0;
            
            float dotProduct = 0;
            float normA = 0;
            float normB = 0;
            
            for (int i = 0; i < vectorA.Length; i++)
            {
                dotProduct += vectorA[i] * vectorB[i];
                normA += vectorA[i] * vectorA[i];
                normB += vectorB[i] * vectorB[i];
            }
            
            return dotProduct / (float)(Math.Sqrt(normA) * Math.Sqrt(normB));
        }
        catch
        {
            return 0;
        }
    }

    /// <summary>
    /// 构建上下文
    /// </summary>
    /// <summary>
    /// 构建RAGFlow上下文（优化版）
    /// </summary>
    private async Task<string> BuildContext(CustomerServiceRequest input, List<Admin.NET.Application.Entity.KnowledgeBase> knowledge)
    {
        var contextBuilder = new StringBuilder();
        
        // 1. 用户查询信息
        contextBuilder.AppendLine("=== 用户查询信息 ===");
        contextBuilder.AppendLine($"用户：{input.UserName}");
        contextBuilder.AppendLine($"问题：{input.Message}");
        contextBuilder.AppendLine($"对话ID：{input.ConversationId}");
        contextBuilder.AppendLine($"时间：{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
        contextBuilder.AppendLine();
        
        // 2. 相关知识库内容（结构化）
        if (knowledge.Any())
        {
            contextBuilder.AppendLine("=== 相关知识库 ===");
            for (int i = 0; i < knowledge.Count && i < 5; i++)
            {
                var k = knowledge[i];
                contextBuilder.AppendLine($"【知识条目 {i + 1}】");
                contextBuilder.AppendLine($"标题：{k.Title}");
                contextBuilder.AppendLine($"分类：{k.Category}");
                contextBuilder.AppendLine($"关键词：{k.Keywords}");
                contextBuilder.AppendLine($"内容：{k.Content}");
                contextBuilder.AppendLine($"更新时间：{k.UpdateTime:yyyy-MM-dd HH:mm:ss}");
                contextBuilder.AppendLine();
            }
        }
        else
        {
            contextBuilder.AppendLine("=== 知识库状态 ===");
            contextBuilder.AppendLine("未找到相关知识条目");
            contextBuilder.AppendLine();
        }
        
        // 3. 对话历史（最近5条）
        var history = await GetConversationHistory(input.ConversationId);
        if (history.Any())
        {
            contextBuilder.AppendLine("=== 对话历史 ===");
            var recentHistory = history.TakeLast(5).ToList();
            foreach (var msg in recentHistory)
            {
                var role = msg.IsFromUser ? "用户" : "AI助手";
                contextBuilder.AppendLine($"[{msg.Timestamp:HH:mm:ss}] {role}：{msg.Message}");
            }
            contextBuilder.AppendLine();
        }
        
        // 4. 系统状态信息
        contextBuilder.AppendLine("=== 系统状态 ===");
        contextBuilder.AppendLine($"当前时间：{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
        contextBuilder.AppendLine($"RAGFlow集成：已启用");
        contextBuilder.AppendLine($"知识库条目数：{knowledge.Count}");
        contextBuilder.AppendLine($"对话历史条数：{history.Count}");
        contextBuilder.AppendLine();
        
        // 5. 业务数据提示
        contextBuilder.AppendLine("=== 可用业务数据 ===");
        contextBuilder.AppendLine("- 库存数据：可查询商品库存、SKU信息");
        contextBuilder.AppendLine("- 订单数据：可查询销售订单、采购订单状态");
        contextBuilder.AppendLine("- 仓库数据：可查询仓库信息、操作记录");
        contextBuilder.AppendLine("- 客户数据：可查询客户信息、联系方式");
        contextBuilder.AppendLine("- 供应商数据：可查询供应商信息、合作状态");
        contextBuilder.AppendLine();
        
        return contextBuilder.ToString();
    }

    /// <summary>
    /// 生成回复
    /// </summary>
    private async Task<string> GenerateResponse(string userMessage, string context, UserIntent intent)
    {
        // 检查是否使用RAGFlow
        var useRAGFlow = _configuration.GetValue<bool>("RAGSettings:UseRAGFlow", false);
        Console.WriteLine($"UseRAGFlow配置值: {useRAGFlow}");
        
        if (useRAGFlow)
        {
            Console.WriteLine("使用RAGflow智能体生成回复");
            return await GenerateRAGFlowResponseDirect(userMessage, 0, "");
        }
        
        Console.WriteLine("使用本地数据分析生成回复");
        
        // 使用数据分析生成智能回复
        var dataAnalysis = await QueryDatabaseAndAnalyze(userMessage, intent);
        
        // 根据意图类型生成不同的回复
        switch (intent.Type)
        {
            case "inventory_query":
                return await GenerateInventoryResponseWithData(userMessage, context, dataAnalysis);
            case "sales_order_query":
                return await GenerateOrderResponseWithData(userMessage, context, dataAnalysis);
            case "customer_query":
                return await GenerateCustomerResponseWithData(userMessage, context, dataAnalysis);
            case "warehouse_query":
                return await GenerateWarehouseResponseWithData(userMessage, context, dataAnalysis);
            case "system_help":
                return await GenerateHelpResponseWithData(userMessage, context, dataAnalysis);
            case "error_report":
                return await GenerateErrorResponseWithData(userMessage, context, dataAnalysis);
            default:
                return await GenerateGeneralResponseWithData(userMessage, context, dataAnalysis);
        }
    }

    /// <summary>
    /// 使用RAGFlow生成回复
    /// </summary>
    /// <summary>
    /// 直接调用RAGFLOW生成回复，不进行任何知识检索或上下文构建
    /// </summary>
    private async Task<string> GenerateRAGFlowResponseDirect(string userMessage, long userId, string conversationId)
    {
        try
        {
            // 如果用户询问偏好，尝试从个人记忆向量库直接提取答案（即使DirectAnswerByMemory为false也尝试）
            // 这样可以确保即使前端清空了对话记录，也能从向量库中找到记忆
            if (IsAskPreference(userMessage))
            {
                Console.WriteLine($"[DirectAnswer] 检测到偏好查询，尝试从个人记忆向量库提取答案...");
                
                // 优先从个人记忆向量库提取（更可靠，不受对话记录影响）
                var memories = await SearchPersonalMemoryAsync(userId, userMessage, 10);
                if (memories != null && memories.Count > 0)
                {
                    // 找出所有包含"我喜欢"的记忆
                    var likeMemories = memories
                        .Where(m => m.Content.Contains("我喜欢") || m.Content.Contains("是我喜欢的"))
                        .OrderByDescending(m => m.Score)
                        .ToList();
                    
                    if (likeMemories.Count > 0)
                    {
                        // 提取第一个高分的记忆中的喜好对象
                        var topMemory = likeMemories[0].Content;
                        var extracted = ExtractLikeFromSingleMessage(topMemory);
                        
                        if (!string.IsNullOrEmpty(extracted))
                        {
                            Console.WriteLine($"[DirectAnswer] ✅ 从个人记忆向量库直接提取到答案: {extracted} (来源: {Truncate(topMemory, 50)})");
                            return $"你喜欢{extracted}哦~ 😊";
                        }
                    }
                }
                
                // 兜底：从数据库对话历史提取（如果向量库没找到）
                var history = await GetConversationHistory(conversationId);
                if (history != null && history.Count > 0)
                {
                    var extracted = ExtractLikeFromMessages(history?.Where(h => h.IsFromUser).Select(h => h.Message));
                    if (!string.IsNullOrEmpty(extracted))
                    {
                        Console.WriteLine($"[DirectAnswer] 从对话历史直接提取到答案: {extracted}");
                        return $"你喜欢{extracted}哦~ 😊";
                    }
                }
                
                Console.WriteLine($"[DirectAnswer] ⚠️ 未找到直接答案，将使用RAGFlow智能回答");
            }

            var ragFlowUrl = _configuration["RAGSettings:RAGFlowUrl"] ?? "http://localhost:8080";
            var ragFlowApiKey = _configuration["RAGSettings:RAGFlowApiKey"];
            var chatEndpoint = _configuration["RAGSettings:RAGFlowChatEndpoint"] ?? "/api/v1/chats_openai/3d3fddd0b08711f08fe002b3fa7c3931/chat/completions";
            var ragFlowModel = _configuration["RAGSettings:RAGFlowModel"] ?? "ragflow";

            // 个人记忆上下文
            var memoryContext = await BuildPersonalMemoryContextAsync(userId, userMessage);

            // 最近对话历史（当前会话）
            var historyContext = await BuildRecentHistoryContextAsync(conversationId);

            // 使用明确的系统提示，包含个人记忆/最近对话历史，要求基于这些上下文进行推理回答
            var systemPrompt = new StringBuilder();
            systemPrompt.AppendLine("你是小智，一个活泼可爱的WMS/MES智能助手。请用简单易懂的语言回答用户问题，经常使用emoji表情。");
            
            // 先添加对话历史（让模型先看到上下文）
            if (!string.IsNullOrEmpty(historyContext))
            {
                systemPrompt.AppendLine();
                systemPrompt.AppendLine(historyContext);
            }
            
            // 再添加个人记忆（补充信息）
            if (!string.IsNullOrEmpty(memoryContext))
            {
                systemPrompt.AppendLine();
                systemPrompt.AppendLine(memoryContext);
            }
            
            // 如果用户询问偏好，特别强调从个人记忆中提取
            var userMessageLower = userMessage.ToLower();
            var isAskingPreference = userMessageLower.Contains("我喜欢什么") || userMessageLower.Contains("我喜欢啥") || 
                                     userMessageLower.Contains("我的喜好") || userMessageLower.Contains("我偏好什么") ||
                                     userMessageLower.Contains("喜欢什么") || userMessageLower.Contains("喜欢啥") ||
                                     userMessageLower.Contains("喜欢吃什么") || userMessageLower.Contains("喜欢什么动漫") ||
                                     userMessageLower.Contains("喜欢什么动画") || userMessageLower.Contains("我喜欢吃什么");
            
            if (isAskingPreference)
            {
                if (!string.IsNullOrEmpty(memoryContext))
                {
                    // 有记忆的情况：强制使用记忆回答
                    systemPrompt.AppendLine();
                    systemPrompt.AppendLine("🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨");
                    systemPrompt.AppendLine("🚨【最高优先级指令】用户正在询问个人偏好/喜好！🚨");
                    systemPrompt.AppendLine("🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨");
                    systemPrompt.AppendLine();
                    systemPrompt.AppendLine("上面的【个人记忆】部分包含了用户之前明确表达过的喜好，你必须100%基于这些记忆回答！");
                    systemPrompt.AppendLine();
                    systemPrompt.AppendLine("【执行步骤】（严格按照以下步骤，不要跳过任何一步）：");
                    systemPrompt.AppendLine("1. 立即查看上面的\"=== 【重要】用户个人记忆（必须使用） ===\"部分");
                    systemPrompt.AppendLine("2. 【关键】如果存在【核心记忆】部分，这是唯一需要关注的内容！忽略其他所有记忆！");
                    systemPrompt.AppendLine("3. 从【核心记忆】中直接使用\"提取内容\"字段的值（例如：如果记忆显示\"提取内容: 龙族\"，直接回答\"你喜欢《龙族》这部动漫哦~ 😊\"）");
                    systemPrompt.AppendLine("4. 如果【核心记忆】有多条，使用分数最高的那一条（通常是最相关的那条）");
                    systemPrompt.AppendLine("5. 如果没有【核心记忆】，则从其他记忆中提取具体的喜好对象（例如：\"我喜欢葡萄\" → 提取\"葡萄\"）");
                    systemPrompt.AppendLine("6. 直接回答用户的喜好，格式：\"你喜欢[提取的内容]哦~ 😊\"");
                    systemPrompt.AppendLine();
                    systemPrompt.AppendLine("⚠️ 特别强调：如果看到【核心记忆】部分，必须使用它！不要看其他记忆！不要猜测！");
                    systemPrompt.AppendLine();
                    systemPrompt.AppendLine("【回答示例】（严格按照以下格式）：");
                    systemPrompt.AppendLine("- 记忆：\"【用户说】我喜欢葡萄\" → 回答：\"你喜欢葡萄哦~ 😊\"");
                    systemPrompt.AppendLine("- 记忆：\"【用户说】龙族是我喜欢的动漫\"（提取内容: 龙族） → 回答：\"你喜欢《龙族》这部动漫哦~ 😊\"");
                    systemPrompt.AppendLine("- 记忆：\"【用户说】我喜欢吃葡萄\" → 回答：\"你喜欢吃葡萄哦~ 😊\"");
                    systemPrompt.AppendLine();
                    systemPrompt.AppendLine("⚠️⚠️⚠️⚠️⚠️【严格禁止】⚠️⚠️⚠️⚠️⚠️：");
                    systemPrompt.AppendLine("- ❌ 绝对禁止说\"虽然现在还不清楚你喜欢什么\"（记忆中有数据，必须使用！）");
                    systemPrompt.AppendLine("- ❌ 禁止反问\"你想不起来了吗\"、\"让我猜猜\"");
                    systemPrompt.AppendLine("- ❌ 禁止给出通用的建议或列表（如\"葡萄、苹果、香蕉\"）");
                    systemPrompt.AppendLine("- ❌ 禁止说\"我没有相关记忆\"或\"让我查看一下\"");
                    systemPrompt.AppendLine("- ❌ 禁止提供知识库中的通用信息");
                    systemPrompt.AppendLine("- ✅ 必须使用【核心记忆】或【个人记忆】中的具体内容，直接回答，不要猜测！");
                    systemPrompt.AppendLine();
                    systemPrompt.AppendLine("⚠️ 重要提醒：如果【核心记忆】部分有数据，必须使用它！不要忽略！");
                    systemPrompt.AppendLine();
                }
                else
                {
                    // 没有记忆的情况：从对话历史中查找
                    systemPrompt.AppendLine();
                    systemPrompt.AppendLine("⚠️ 注意：用户询问偏好，但个人记忆向量库中没有检索到相关记录。");
                    systemPrompt.AppendLine("请检查上面的【最近对话历史】部分，看看是否有用户表达过的偏好。");
                    systemPrompt.AppendLine("如果对话历史中有\"我喜欢X\"的记录，直接回答\"你喜欢X\"。");
                    systemPrompt.AppendLine();
                }
            }
            else
            {
                // 非偏好查询：普通回答规则
                systemPrompt.AppendLine();
                systemPrompt.AppendLine("【回答规则】");
                systemPrompt.AppendLine("1. 优先使用上面的个人记忆，这些是用户之前明确表达过的信息");
                systemPrompt.AppendLine("2. 其次参考最近对话历史，了解当前对话上下文");
                systemPrompt.AppendLine("3. 当这些信息包含明确答案时，直接作答，不要猜测");
                systemPrompt.AppendLine("4. 信息不足时，再进行合理推断或礼貌询问");
                systemPrompt.AppendLine();
            }
            systemPrompt.AppendLine();
            systemPrompt.AppendLine("重要：请直接回答用户问题，绝对不要使用以下任何前缀：");
            systemPrompt.AppendLine("- 不要使用'根据知识库'");
            systemPrompt.AppendLine("- 不要使用'基于知识库'");
            systemPrompt.AppendLine("- 不要使用'查阅文档'");
            systemPrompt.AppendLine("- 不要使用'根据资料'");
            systemPrompt.AppendLine("- 不要使用任何表示信息来源的词汇");
            systemPrompt.AppendLine();
            systemPrompt.AppendLine("请直接给出答案，就像朋友之间的对话一样自然。");

            // 打印调试：个人记忆与最近历史已注入到 system 提示
            try
            {
                var preview = systemPrompt.ToString();
                Console.WriteLine("[RAGFlow][SystemPrompt] \n" + Truncate(preview, 2000));
                Console.WriteLine($"[RAGFlow][SystemPrompt] 是否偏好查询: {isAskingPreference}, 是否有个人记忆: {!string.IsNullOrEmpty(memoryContext)}");
            }
            catch { }

            var requestBody = new
            {
                model = ragFlowModel,
                messages = new[]
                {
                    new { role = "system", content = systemPrompt.ToString() },
                    new { role = "user", content = userMessage }
                },
                temperature = 0.7,
                max_tokens = 2000,
                stream = false
            };

            var json = JsonSerializer.Serialize(requestBody);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            using var httpClient = new HttpClient();
            httpClient.Timeout = TimeSpan.FromSeconds(120);
            
            if (!string.IsNullOrEmpty(ragFlowApiKey))
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ragFlowApiKey);
            }

            Console.WriteLine($"直接调用RAGFlow API: {ragFlowUrl}{chatEndpoint}");
            var response = await httpClient.PostAsync($"{ragFlowUrl}{chatEndpoint}", content);
            
            if (!response.IsSuccessStatusCode)
            {
                var errorContent = await response.Content.ReadAsStringAsync();
                Console.WriteLine($"RAGFlow API错误: {response.StatusCode} - {errorContent}");
                return "抱歉，RAGFLOW服务暂时不可用，请稍后重试。";
            }

            var responseContent = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"RAGFlow响应: {responseContent}");
            
            // 优先尝试解析JSON响应
            try
            {
                var ragFlowResponse = JsonSerializer.Deserialize<RAGFlowResponse>(responseContent);
                
                if (ragFlowResponse?.Choices?.Length > 0)
                {
                    var firstChoice = ragFlowResponse.Choices[0];
                    
                    if (firstChoice?.Message?.Content != null)
                    {
                        var ragContent = firstChoice.Message.Content;
                        Console.WriteLine($"直接返回RAGflow原始回答: {ragContent}");
                        
                        // 过滤掉知识库相关的前缀
                        var filteredContent = FilterKnowledgeBasePrefixes(ragContent);
                        Console.WriteLine($"过滤后的回答: {filteredContent}");
                        
                        return filteredContent;
                    }
                }
                
                Console.WriteLine("RAGflow响应中未找到有效内容");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"JSON解析失败: {ex.Message}");
            }
            
            // 尝试解析流式响应（备用）
            var fullContent = ParseRAGFlowStreamResponse(responseContent);
            if (!string.IsNullOrEmpty(fullContent))
            {
                Console.WriteLine($"流式解析成功，内容: {fullContent}");
                
                // 过滤掉知识库相关的前缀
                var filteredContent = FilterKnowledgeBasePrefixes(fullContent);
                Console.WriteLine($"流式响应过滤后的回答: {filteredContent}");
                
                return filteredContent;
            }
            
            Console.WriteLine("所有解析方法都失败");
            return "抱歉，无法解析RAGFLOW的回答，请稍后重试。";
        }
        catch (Exception ex)
        {
            Console.WriteLine($"RAGFlow API调用失败: {ex.Message}");
            Console.WriteLine($"异常详情: {ex}");
            return "抱歉，RAGFLOW服务调用失败，请稍后重试。";
        }
    }

    private bool IsAskPreference(string msg)
    {
        if (string.IsNullOrWhiteSpace(msg)) return false;
        var text = msg.Trim();
        var patterns = new[]
        {
            "我喜欢什么",
            "我喜不喜欢什么",
            "我的喜好",
            "我偏好什么",
            "我喜欢啥",
            "我喜欢哪种"
        };
        return patterns.Any(p => text.Contains(p));
    }

    private async Task<string> TryGetUserPreferenceAsync(long userId, string conversationId, string userMessage)
    {
        try
        {
            // 1) 先看最近对话历史中用户显式表达
            var history = await GetConversationHistory(conversationId);
            var fromHistory = ExtractLikeFromMessages(history?.Where(h => h.IsFromUser).Select(h => h.Message));
            if (!string.IsNullOrEmpty(fromHistory)) return fromHistory;

            // 2) 再查个人记忆（按 userId 过滤）
            var memories = await SearchPersonalMemoryAsync(userId, userMessage, 5);
            var fromMemory = ExtractLikeFromMessages(memories?.Where(m => m.Role == "user").Select(m => m.Content));
            if (!string.IsNullOrEmpty(fromMemory)) return fromMemory;
        }
        catch { }
        return null;
    }

    private string ExtractLikeFromMessages(IEnumerable<string> messages)
    {
        if (messages == null) 
        {
            Console.WriteLine("[ExtractLike] messages 为 null");
            return null;
        }
        
        var msgList = messages.ToList();
        Console.WriteLine($"[ExtractLike] 处理 {msgList.Count} 条消息");
        
        // 从后往前遍历（最新的消息在前）
        for (int i = msgList.Count - 1; i >= 0; i--)
        {
            var m = msgList[i];
            if (string.IsNullOrEmpty(m)) continue;
            
            Console.WriteLine($"[ExtractLike] 检查消息: {Truncate(m, 100)}");
            
            // 需要排除的关键词（疑问词和无效词）
            var excludeKeywords = new[] { "什么", "啥", "哪个", "哪些", "多少", "如何", "怎么", "怎样", "?", "？", "呢", "吗" };
            
            // 规则1: 匹配"我喜欢XXX"（精确匹配）
            var match1 = System.Text.RegularExpressions.Regex.Match(m, "我喜欢(?<x>.{1,20})");
            if (match1.Success)
            {
                var x = match1.Groups["x"].Value.Trim().Trim('。', '!', '！', '，', ',', '～', '~', '?', '？');
                // 排除疑问词和无效词
                if (!string.IsNullOrEmpty(x) && x.Length <= 15 && 
                    !excludeKeywords.Any(k => x.Contains(k)) && 
                    x.Length >= 1) // 至少1个字符
                {
                    Console.WriteLine($"[ExtractLike] ✅ 匹配成功: {x}");
                    return x;
                }
                else
                {
                    Console.WriteLine($"[ExtractLike] ⚠️ 匹配但被过滤: {x} (包含疑问词或无效)");
                }
            }
            
            // 规则2: 匹配"我喜欢吃XXX"
            var match2 = System.Text.RegularExpressions.Regex.Match(m, "我喜欢吃(?<x>.{1,20})");
            if (match2.Success)
            {
                var x = match2.Groups["x"].Value.Trim().Trim('。', '!', '！', '，', ',', '～', '~', '?', '？');
                if (!string.IsNullOrEmpty(x) && x.Length <= 15 && 
                    !excludeKeywords.Any(k => x.Contains(k)) && 
                    x.Length >= 1)
                {
                    Console.WriteLine($"[ExtractLike] ✅ 匹配成功(吃): {x}");
                    return x;
                }
                else
                {
                    Console.WriteLine($"[ExtractLike] ⚠️ 匹配但被过滤(吃): {x} (包含疑问词或无效)");
                }
            }
            
            // 规则3: 匹配"我爱XXX"
            var match3 = System.Text.RegularExpressions.Regex.Match(m, "我爱(?<x>.{1,20})");
            if (match3.Success)
            {
                var x = match3.Groups["x"].Value.Trim().Trim('。', '!', '！', '，', ',', '～', '~', '?', '？');
                if (!string.IsNullOrEmpty(x) && x.Length <= 15 && 
                    !excludeKeywords.Any(k => x.Contains(k)) && 
                    x.Length >= 1)
                {
                    Console.WriteLine($"[ExtractLike] ✅ 匹配成功(爱): {x}");
                    return x;
                }
                else
                {
                    Console.WriteLine($"[ExtractLike] ⚠️ 匹配但被过滤(爱): {x} (包含疑问词或无效)");
                }
            }
        }
        
        Console.WriteLine("[ExtractLike] ❌ 未找到匹配的喜好");
        return null;
    }

    /// <summary>
    /// 从单个消息中提取喜好（用于个人记忆）
    /// </summary>
    private string ExtractLikeFromSingleMessage(string message)
    {
        if (string.IsNullOrEmpty(message))
        {
            Console.WriteLine("[ExtractLikeFromSingle] message 为 null");
            return null;
        }
        
        // 需要排除的关键词（疑问词和无效词）
        var excludeKeywords = new[] { "什么", "啥", "哪个", "哪些", "多少", "如何", "怎么", "怎样", "?", "？", "呢", "吗" };
        
        // 只在调试时输出，减少日志噪音
        // Console.WriteLine($"[ExtractLikeFromSingle] 处理消息: {Truncate(message, 100)}");
        
        // 规则1: 匹配"我喜欢XXX"（精确匹配）
        var match1 = System.Text.RegularExpressions.Regex.Match(message, "我喜欢(?<x>.{1,20})");
        if (match1.Success)
        {
            var x = match1.Groups["x"].Value.Trim().Trim('。', '!', '！', '，', ',', '～', '~', '?', '？', '的', '了');
            // 排除疑问词和无效词
            if (!string.IsNullOrEmpty(x) && x.Length <= 15 && 
                !excludeKeywords.Any(k => x.Contains(k)) && 
                x.Length >= 1)
            {
                Console.WriteLine($"[ExtractLikeFromSingle] ✅ 匹配成功: {x}");
                return x;
            }
        }
        
        // 规则2: 匹配"我喜欢吃XXX"
        var match2 = System.Text.RegularExpressions.Regex.Match(message, "我喜欢吃(?<x>.{1,20})");
        if (match2.Success)
        {
            var x = match2.Groups["x"].Value.Trim().Trim('。', '!', '！', '，', ',', '～', '~', '?', '？', '的', '了');
            if (!string.IsNullOrEmpty(x) && x.Length <= 15 && 
                !excludeKeywords.Any(k => x.Contains(k)) && 
                x.Length >= 1)
            {
                Console.WriteLine($"[ExtractLikeFromSingle] ✅ 匹配成功(吃): {x}");
                return x;
            }
        }
        
        // 规则3: 匹配"X是我喜欢的Y"（语序不同，优先级高，因为这种模式更明确）
        var match3 = System.Text.RegularExpressions.Regex.Match(message, "(.{1,20})是我喜欢的(.{0,10})");
        if (match3.Success)
        {
            var x = match3.Groups[1].Value.Trim().Trim('。', '!', '！', '，', ',', '～', '~', '?', '？', '的', '了');
            // 确保提取的是第一个捕获组（X），而不是第二个（Y）
            // 只在调试时输出详细信息
            // Console.WriteLine($"[ExtractLikeFromSingle] 规则3匹配: Groups[0]={match3.Groups[0].Value}, Groups[1]={match3.Groups[1].Value}, Groups[2]={match3.Groups[2].Value}");
            
            if (!string.IsNullOrEmpty(x) && x.Length <= 20 && 
                !excludeKeywords.Any(k => x.Contains(k)) && 
                x.Length >= 1)
            {
                Console.WriteLine($"[ExtractLikeFromSingle] ✅ 匹配成功(是我喜欢的): {x}");
                return x;
            }
            // 只在失败时输出警告
            // else { Console.WriteLine($"[ExtractLikeFromSingle] ⚠️ 规则3匹配但被过滤: x={x}"); }
        }
        
        // 规则4: 匹配"我爱XXX"
        var match4 = System.Text.RegularExpressions.Regex.Match(message, "我爱(?<x>.{1,20})");
        if (match4.Success)
        {
            var x = match4.Groups["x"].Value.Trim().Trim('。', '!', '！', '，', ',', '～', '~', '?', '？', '的', '了');
            if (!string.IsNullOrEmpty(x) && x.Length <= 15 && 
                !excludeKeywords.Any(k => x.Contains(k)) && 
                x.Length >= 1)
            {
                Console.WriteLine($"[ExtractLikeFromSingle] ✅ 匹配成功(爱): {x}");
                return x;
            }
        }
        
        // 只在调试时输出，减少日志噪音
        // Console.WriteLine("[ExtractLikeFromSingle] ❌ 未找到匹配的喜好");
        return null;
    }

    private string Truncate(string text, int max)
    {
        if (string.IsNullOrEmpty(text)) return text;
        return text.Length <= max ? text : text.Substring(0, max) + "... [truncated]";
    }

    /// <summary>
    /// 直接返回RAGFLOW的原始回答内容，不进行任何格式化
    /// </summary>
    private string FormatRAGFlowResponse(string ragContent, string context, UserIntent intent)
    {
        try
        {
            // 直接返回RAGFLOW的原始回答内容，保持完全一致
            Console.WriteLine($"直接返回RAGFLOW原始回答: {ragContent}");
            return ragContent;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"返回RAGFLOW原始回答失败: {ex.Message}");
            return ragContent; // 返回原始内容
        }
    }
    

    /// <summary>
    /// 解析RAGflow流式响应
    /// </summary>
    private string ParseRAGFlowStreamResponse(string responseContent)
    {
        try
        {
            var lines = responseContent.Split('\n');
            var fullContent = new StringBuilder();
            
            foreach (var line in lines)
            {
                if (line.StartsWith("data:"))
                {
                    var jsonData = line.Substring(5).Trim();
                    if (jsonData == "[DONE]")
                        break;
                        
                    try
                    {
                        var chunk = JsonSerializer.Deserialize<RAGFlowStreamChunk>(jsonData);
                        if (chunk?.Choices?.FirstOrDefault()?.Delta?.Content != null)
                        {
                            fullContent.Append(chunk.Choices.FirstOrDefault().Delta.Content);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"解析流式数据块失败: {ex.Message}");
                    }
                }
            }
            
            var result = fullContent.ToString();
            Console.WriteLine($"解析的完整内容: {result}");
            return result;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"解析流式响应失败: {ex.Message}");
            return null;
        }
    }

    /// <summary>
    /// 获取或创建RAGflow聊天ID
    /// </summary>
    private async Task<string> GetOrCreateChatId()
    {
        try
        {
            var ragFlowUrl = _configuration["RAGSettings:RAGFlowUrl"] ?? "http://localhost:8080";
            var ragFlowApiKey = _configuration["RAGSettings:RAGFlowApiKey"];
            
            // 先尝试获取现有的聊天会话
            using var httpClient = new HttpClient();
            if (!string.IsNullOrEmpty(ragFlowApiKey))
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ragFlowApiKey);
            }
            
            var response = await httpClient.GetAsync($"{ragFlowUrl}/api/v1/chats");
            if (response.IsSuccessStatusCode)
            {
                var content = await response.Content.ReadAsStringAsync();
                var chatsResponse = JsonSerializer.Deserialize<RAGFlowChatsResponse>(content);
                
                if (chatsResponse?.Data?.Length > 0)
                {
                    // 返回第一个聊天会话的ID
                    return chatsResponse.Data[0].Id;
                }
            }
            
            // 如果没有现有会话，创建一个新的
            var createRequest = new
            {
                name = "小智客服",
                description = "小智 - WMS系统智能助手，活泼可爱的AI客服"
            };
            
            var json = JsonSerializer.Serialize(createRequest);
            var requestContent = new StringContent(json, Encoding.UTF8, "application/json");
            
            var createResponse = await httpClient.PostAsync($"{ragFlowUrl}/api/v1/chats", requestContent);
            if (createResponse.IsSuccessStatusCode)
            {
                var createContent = await createResponse.Content.ReadAsStringAsync();
                var createChatResponse = JsonSerializer.Deserialize<RAGFlowCreateChatResponse>(createContent);
                
                if (createChatResponse?.Data?.Id != null)
                {
                    return createChatResponse.Data.Id;
                }
            }
            
            // 如果都失败了，返回默认ID
            return "05a754b2b06d11f0a01572de784b3708";
        }
        catch (Exception ex)
        {
            Console.WriteLine($"获取RAGflow聊天ID失败: {ex.Message}");
            return "05a754b2b06d11f0a01572de784b3708"; // 使用已知的ID作为fallback
        }
    }

    /// <summary>
    /// 构建简单的系统提示，与直接调用RAGFLOW保持一致
    /// </summary>
    private string BuildWMSSystemPrompt(string context, UserIntent intent)
    {
        // 使用简单的系统提示，与直接调用RAGFLOW API时保持一致
        return "你是小智，一个活泼可爱的WMS系统智能助手。请用简单易懂的语言回答用户问题，经常使用emoji表情。";
    }

    /// <summary>
    /// 动态查询数据库并生成分析报告
    /// </summary>
    private async Task<string> QueryDatabaseAndAnalyze(string userMessage, UserIntent intent)
    {
        try
        {
            var analysis = new StringBuilder();
            analysis.AppendLine("📊 **实时数据分析报告**");
            analysis.AppendLine();

            // 根据意图类型查询相关数据
            switch (intent.Type)
            {
                case "inventory_query":
                    await AnalyzeInventoryData(analysis);
                    break;
                case "sales_order_query":
                    await AnalyzeSalesOrderData(analysis);
                    break;
                case "customer_query":
                    await AnalyzeCustomerData(analysis);
                    break;
                case "warehouse_query":
                    await AnalyzeWarehouseData(analysis);
                    break;
                default:
                    await AnalyzeGeneralData(analysis);
                    break;
            }

            return analysis.ToString();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"数据库分析失败: {ex.Message}");
            return "📊 数据分析暂时不可用，但我会尽力为您提供帮助！";
        }
    }

    /// <summary>
    /// 分析库存数据
    /// </summary>
    private async Task AnalyzeInventoryData(StringBuilder analysis)
    {
        try
        {
            // 查询商品总数
            var totalGoods = await _knowledgeRepo.CountAsync(x => x.Id > 0);
            analysis.AppendLine($"📦 **库存概况**");
            analysis.AppendLine($"- 系统中共有 {totalGoods} 个商品记录");
            
            // 查询最近入库记录
            var recentInbound = await _instockOrderRepo.CountAsync(x => x.CreateTime >= DateTime.Now.AddDays(-7));
            analysis.AppendLine($"- 最近7天入库单数: {recentInbound} 单");
            
            // 查询最近出库记录
            var recentOutbound = await _outstockOrderRepo.CountAsync(x => x.CreateTime >= DateTime.Now.AddDays(-7));
            analysis.AppendLine($"- 最近7天出库单数: {recentOutbound} 单");
            
            analysis.AppendLine();
            analysis.AppendLine("💡 **建议**：");
            analysis.AppendLine("- 定期检查库存预警设置");
            analysis.AppendLine("- 关注高频出入库商品");
            analysis.AppendLine("- 及时处理积压库存");
        }
        catch (Exception ex)
        {
            analysis.AppendLine($"❌ 库存数据分析失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 分析销售订单数据
    /// </summary>
    private async Task AnalyzeSalesOrderData(StringBuilder analysis)
    {
        try
        {
            // 查询订单总数
            var totalOrders = await _salesOrderRepo.CountAsync(x => x.Id > 0);
            analysis.AppendLine($"📋 **订单概况**");
            analysis.AppendLine($"- 系统中共有 {totalOrders} 个销售订单");
            
            // 查询最近订单
            var recentOrders = await _salesOrderRepo.CountAsync(x => x.CreateTime >= DateTime.Now.AddDays(-30));
            analysis.AppendLine($"- 最近30天新增订单: {recentOrders} 单");
            
            // 查询待处理订单
            var pendingOrders = await _salesOrderRepo.CountAsync(x => x.DocumentStatus == DocumentStatusEnum.Draft);
            analysis.AppendLine($"- 待处理订单: {pendingOrders} 单");
            
            analysis.AppendLine();
            analysis.AppendLine("💡 **建议**：");
            analysis.AppendLine("- 及时处理待审核订单");
            analysis.AppendLine("- 关注订单处理时效");
            analysis.AppendLine("- 定期分析订单趋势");
        }
        catch (Exception ex)
        {
            analysis.AppendLine($"❌ 订单数据分析失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 分析客户数据
    /// </summary>
    private async Task AnalyzeCustomerData(StringBuilder analysis)
    {
        try
        {
            // 查询客户总数
            var totalCustomers = await _salesOrderRepo.CountAsync(x => x.Id > 0);
            analysis.AppendLine($"👥 **客户概况**");
            analysis.AppendLine($"- 系统中共有 {totalCustomers} 个客户记录");
            
            // 查询活跃客户（最近30天有订单）
            var activeCustomers = await _salesOrderRepo.CountAsync(x => x.CreateTime >= DateTime.Now.AddDays(-30));
            analysis.AppendLine($"- 最近30天活跃客户: {activeCustomers} 个");
            
            analysis.AppendLine();
            analysis.AppendLine("💡 **建议**：");
            analysis.AppendLine("- 维护客户关系管理");
            analysis.AppendLine("- 关注客户满意度");
            analysis.AppendLine("- 定期客户回访");
        }
        catch (Exception ex)
        {
            analysis.AppendLine($"❌ 客户数据分析失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 分析仓库数据
    /// </summary>
    private async Task AnalyzeWarehouseData(StringBuilder analysis)
    {
        try
        {
            await Task.CompletedTask; // 避免async警告
            
            analysis.AppendLine("🏭 **仓库概况**");
            analysis.AppendLine("- 仓库管理系统运行正常");
            analysis.AppendLine("- 支持多仓库管理");
            analysis.AppendLine("- 实时库存监控");
            
            analysis.AppendLine();
            analysis.AppendLine("💡 **建议**：");
            analysis.AppendLine("- 定期进行仓库盘点");
            analysis.AppendLine("- 优化仓库布局");
            analysis.AppendLine("- 提高仓库作业效率");
        }
        catch (Exception ex)
        {
            analysis.AppendLine($"❌ 仓库数据分析失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 分析通用数据
    /// </summary>
    private async Task AnalyzeGeneralData(StringBuilder analysis)
    {
        try
        {
            await Task.CompletedTask; // 避免async警告
            
            analysis.AppendLine("📊 **系统概况**");
            analysis.AppendLine("- WMS系统运行正常");
            analysis.AppendLine("- 数据实时同步");
            analysis.AppendLine("- 支持多种业务场景");
            
            analysis.AppendLine();
            analysis.AppendLine("💡 **建议**：");
            analysis.AppendLine("- 定期备份重要数据");
            analysis.AppendLine("- 关注系统性能指标");
            analysis.AppendLine("- 及时处理系统告警");
        }
        catch (Exception ex)
        {
            analysis.AppendLine($"❌ 通用数据分析失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 过滤掉知识库相关的前缀
    /// </summary>
    private string FilterKnowledgeBasePrefixes(string content)
    {
        if (string.IsNullOrEmpty(content))
            return content;

        Console.WriteLine($"开始过滤知识库前缀，原始内容: {content}");

        var filteredContent = content;
        
        // 使用正则表达式匹配所有可能的模式
        var patterns = new[]
        {
            @"^根据知识库[^，,]*[,，]\s*",
            @"^基于知识库[^，,]*[,，]\s*",
            @"^查阅文档[^，,]*[,，]\s*",
            @"^根据资料[^，,]*[,，]\s*",
            @"^根据文档[^，,]*[,，]\s*",
            @"^基于文档[^，,]*[,，]\s*",
            @"^根据系统资料[^，,]*[,，]\s*",
            @"^基于系统资料[^，,]*[,，]\s*",
            @"^根据知识库\s*[,，]\s*",
            @"^基于知识库\s*[,，]\s*",
            @"^查阅文档\s*[,，]\s*",
            @"^根据资料\s*[,，]\s*",
            @"^根据文档\s*[,，]\s*",
            @"^基于文档\s*[,，]\s*",
            @"^根据系统资料\s*[,，]\s*",
            @"^基于系统资料\s*[,，]\s*"
        };
        
        foreach (var pattern in patterns)
        {
            var regex = new System.Text.RegularExpressions.Regex(pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            var match = regex.Match(filteredContent);
            if (match.Success)
            {
                Console.WriteLine($"匹配到模式: {pattern}, 匹配内容: {match.Value}");
                filteredContent = filteredContent.Substring(match.Length).TrimStart();
                Console.WriteLine($"过滤后内容: {filteredContent}");
                break;
            }
        }

        // 如果正则表达式没有匹配到，尝试精确匹配
        if (filteredContent == content)
        {
            var exactPrefixes = new[]
            {
                "根据知识库,",
                "根据知识库，",
                "根据知识库内容,",
                "根据知识库内容，",
                "基于知识库,",
                "基于知识库，",
                "基于知识库内容,",
                "基于知识库内容，",
                "查阅文档,",
                "查阅文档，",
                "查阅文档内容,",
                "查阅文档内容，",
                "根据资料,",
                "根据资料，",
                "根据资料内容,",
                "根据资料内容，",
                "根据文档,",
                "根据文档，",
                "根据文档内容,",
                "根据文档内容，",
                "基于文档,",
                "基于文档，",
                "基于文档内容,",
                "基于文档内容，",
                "根据系统资料,",
                "根据系统资料，",
                "根据系统资料内容,",
                "根据系统资料内容，",
                "基于系统资料,",
                "基于系统资料，",
                "基于系统资料内容,",
                "基于系统资料内容，"
            };

            foreach (var prefix in exactPrefixes)
            {
                if (filteredContent.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
                {
                    Console.WriteLine($"精确匹配到前缀: {prefix}");
                    filteredContent = filteredContent.Substring(prefix.Length).TrimStart();
                    Console.WriteLine($"过滤后内容: {filteredContent}");
                    break;
                }
            }
        }

        Console.WriteLine($"最终过滤结果: {filteredContent}");
        return filteredContent;
    }

    /// <summary>
    /// 直接返回原始用户消息，不添加任何额外内容
    /// </summary>
    private async Task<string> BuildEnhancedUserMessage(string userMessage, UserIntent intent)
    {
        // 直接返回原始用户消息，与直接调用RAGFLOW API时保持一致
        return userMessage;
    }

    /// <summary>
    /// 生成文本嵌入向量（调用配置的Embedding API；失败时退避到简化向量）
    /// </summary>
    private async Task<float[]> GenerateEmbeddingAsync(string text)
    {
        try
        {
            if (string.IsNullOrWhiteSpace(text))
            {
                Console.WriteLine("[Embedding] 文本为空，使用随机向量");
                return GenerateSimpleVector("");
            }

            var apiKey = _configuration["RAGSettings:EmbeddingApiKey"];
            var apiUrl = _configuration["RAGSettings:EmbeddingApiUrl"];
            var model = _configuration["RAGSettings:EmbeddingModel"] ?? "ragflow";

            if (string.IsNullOrEmpty(apiUrl))
            {
                Console.WriteLine("[Embedding] EmbeddingApiUrl配置缺失，使用随机向量");
                return GenerateSimpleVector(text);
            }

            var requestBody = new { input = text, model = model };
            var json = JsonSerializer.Serialize(requestBody);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            using var httpClient = new HttpClient();
            
            // 只有当 apiKey 不为空时才设置 Authorization header（Ollama 不需要）
            if (!string.IsNullOrWhiteSpace(apiKey))
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
            }
            
            var endpoint = apiUrl.EndsWith("/embeddings", StringComparison.OrdinalIgnoreCase)
                ? apiUrl
                : $"{apiUrl.TrimEnd('/')}/embeddings";
            
            Console.WriteLine($"[Embedding] 调用API: {endpoint}, model={model}");
            
            var response = await httpClient.PostAsync(endpoint, content);
            
            if (!response.IsSuccessStatusCode)
            {
                var error = await response.Content.ReadAsStringAsync();
                Console.WriteLine($"[Embedding] API调用失败: {response.StatusCode}, {error}");
                return GenerateSimpleVector(text);
            }

            var responseContent = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"[Embedding] 原始响应长度: {responseContent.Length}");
            Console.WriteLine($"[Embedding] 原始响应前500字符: {Truncate(responseContent, 500)}");
            
            // 尝试多种格式解析（兼容 Ollama、OpenAI、RAGFlow 等）
            float[] embedding = null;
            
            try
            {
                // 格式1: 标准 OpenAI 格式 {"data": [{"embedding": [...]}]}
                var embeddingResponse = JsonSerializer.Deserialize<EmbeddingResponseLike>(responseContent);
                
                if (embeddingResponse?.Data != null && embeddingResponse.Data.Length > 0)
                {
                    embedding = embeddingResponse.Data[0]?.Embedding;
                    
                    if (embedding != null && embedding.Length > 0)
                    {
                        Console.WriteLine($"[Embedding] ✅ 成功（标准格式），维度={embedding.Length}");
                        return embedding;
                    }
                    else
                    {
                        Console.WriteLine($"[Embedding] ⚠️ 标准格式解析：Data数组存在但embedding字段为空或长度为0");
                    }
                }
                else
                {
                    Console.WriteLine($"[Embedding] ⚠️ 标准格式解析：Data数组为空或不存在，尝试备用格式");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[Embedding] ⚠️ 标准格式解析失败: {ex.Message}");
            }
            
            // 格式2: 使用 JsonDocument 灵活解析（兼容 Ollama 格式）
            try
            {
                using var doc = JsonDocument.Parse(responseContent);
                var root = doc.RootElement;
                
                // 尝试查找 data 字段
                if (root.TryGetProperty("data", out var dataElement) && dataElement.ValueKind == JsonValueKind.Array)
                {
                    var arrayLength = dataElement.GetArrayLength();
                    Console.WriteLine($"[Embedding] 找到data数组，长度={arrayLength}");
                    
                    if (arrayLength > 0)
                    {
                        var firstItem = dataElement[0];
                        Console.WriteLine($"[Embedding] 第一个元素类型: {firstItem.ValueKind}");
                        
                        // 尝试多种可能的字段名
                        if (firstItem.TryGetProperty("embedding", out var embeddingElement))
                        {
                            Console.WriteLine($"[Embedding] 找到embedding字段，类型: {embeddingElement.ValueKind}, 长度: {(embeddingElement.ValueKind == JsonValueKind.Array ? embeddingElement.GetArrayLength() : -1)}");
                            
                            // 确保在JsonDocument dispose之前提取数据
                            var embeddingText = embeddingElement.GetRawText();
                            embedding = JsonSerializer.Deserialize<float[]>(embeddingText);
                            
                            if (embedding != null && embedding.Length > 0)
                            {
                                Console.WriteLine($"[Embedding] ✅ 成功（备用格式），维度={embedding.Length}, 前3个值: [{embedding[0]}, {embedding[1]}, {embedding[2]}]");
                                return embedding;
                            }
                            else
                            {
                                Console.WriteLine($"[Embedding] ⚠️ 备用格式解析后embedding仍为null或空");
                            }
                        }
                        else if (firstItem.TryGetProperty("vector", out var vectorElement))
                        {
                            Console.WriteLine($"[Embedding] 找到vector字段");
                            var vectorText = vectorElement.GetRawText();
                            embedding = JsonSerializer.Deserialize<float[]>(vectorText);
                            
                            if (embedding != null && embedding.Length > 0)
                            {
                                Console.WriteLine($"[Embedding] ✅ 成功（vector格式），维度={embedding.Length}");
                                return embedding;
                            }
                        }
                        else
                        {
                            Console.WriteLine($"[Embedding] ⚠️ 第一个元素中未找到embedding或vector字段");
                            Console.WriteLine($"[Embedding] 第一个元素的所有属性: {string.Join(", ", firstItem.EnumerateObject().Select(p => p.Name))}");
                        }
                    }
                }
                else
                {
                    Console.WriteLine($"[Embedding] ⚠️ 未找到data字段或data不是数组，root类型: {root.ValueKind}");
                }
                
                // 如果直接返回数组格式（某些 API 可能这样）
                if (root.ValueKind == JsonValueKind.Array && root.GetArrayLength() > 0)
                {
                    Console.WriteLine($"[Embedding] 根元素是数组");
                    var firstItem = root[0];
                    if (firstItem.TryGetProperty("embedding", out var embeddingElement))
                    {
                        var embeddingText = embeddingElement.GetRawText();
                        embedding = JsonSerializer.Deserialize<float[]>(embeddingText);
                        if (embedding != null && embedding.Length > 0)
                        {
                            Console.WriteLine($"[Embedding] ✅ 成功（数组格式），维度={embedding.Length}");
                            return embedding;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[Embedding] 备用格式解析失败: {ex.Message}");
                Console.WriteLine($"[Embedding] 异常堆栈: {ex.StackTrace}");
            }
            
            // 所有解析都失败，打印响应内容前200字符用于调试
            var preview = responseContent.Length > 200 ? responseContent.Substring(0, 200) : responseContent;
            Console.WriteLine($"[Embedding] 响应中无有效向量，使用随机向量。响应预览: {preview}");
            return GenerateSimpleVector(text);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"[Embedding] 异常: {ex.Message}");
            return GenerateSimpleVector(text);
        }
    }

    /// <summary>
    /// 简化的向量生成（退避方案）
    /// </summary>
    private float[] GenerateSimpleVector(string text)
    {
        var hash = text.GetHashCode();
        int dimension = 384;
        int.TryParse(_configuration["RAGSettings:VectorDimension"], out dimension);
        if (dimension <= 0) dimension = 384;
        var vector = new float[dimension];
        var random = new Random(hash);
        for (int i = 0; i < vector.Length; i++)
        {
            vector[i] = (float)(random.NextDouble() * 2 - 1);
        }
        return vector;
    }

    /// <summary>
    /// 将消息写入个人记忆（Qdrant）
    /// </summary>
    private async Task UpsertPersonalMemoryAsync(long userId, string conversationId, bool isUser, string text)
    {
        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collection = _configuration["RAGSettings:QdrantMemoryCollection"] ?? "wms_personal_memory";
            await EnsureQdrantCollectionAsync(collection);
            var vector = await GenerateEmbeddingAsync(text);

            var payload = new
            {
                user_id = userId,
                conversation_id = conversationId,
                role = isUser ? "user" : "assistant",
                content = text,
                created_at = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            };

            var pointId = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() * 10 + (isUser ? 1 : 2);

            var body = new
            {
                points = new[]
                {
                    new { id = pointId, vector = vector, payload = payload }
                }
            };

            var json = JsonSerializer.Serialize(body);
            using var httpClient = new HttpClient();
            var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
            var resp = await httpClient.PutAsync($"{qdrantUrl}/collections/{collection}/points", httpContent);
            resp.EnsureSuccessStatusCode();

            try
            {
                Console.WriteLine($"[Memory][Upsert] userId={userId}, conv={conversationId}, role={(isUser ? "user" : "assistant")}, text={Truncate(text, 200)}");
            }
            catch { }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"写入个人记忆失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 确保Qdrant集合存在（不存在则按VectorDimension创建）
    /// </summary>
    private async Task EnsureQdrantCollectionAsync(string collection)
    {
        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            using var http = new HttpClient();
            var get = await http.GetAsync($"{qdrantUrl}/collections/{collection}");
            if (get.IsSuccessStatusCode) return;

            var dim = _configuration.GetValue<int>("RAGSettings:VectorDimension", 384);
            var createReq = new
            {
                vectors = new { size = dim > 0 ? dim : 384, distance = "Cosine" }
            };
            var json = JsonSerializer.Serialize(createReq);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            var put = await http.PutAsync($"{qdrantUrl}/collections/{collection}", content);
            if (!put.IsSuccessStatusCode)
            {
                Console.WriteLine($"创建Qdrant集合失败: {put.StatusCode}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"EnsureQdrantCollection失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 组装当前会话最近历史上下文
    /// </summary>
    private async Task<string> BuildRecentHistoryContextAsync(string conversationId)
    {
        if (string.IsNullOrWhiteSpace(conversationId)) return string.Empty;
        var history = await GetConversationHistory(conversationId);
        if (history == null || history.Count == 0) return string.Empty;
        var recent = history.TakeLast(5).ToList();
        var sb = new StringBuilder();
        sb.AppendLine("=== 最近对话历史（节选） ===");
        foreach (var msg in recent)
        {
            var role = msg.IsFromUser ? "用户" : "小智";
            sb.AppendLine($"- {role}：{msg.Message}");
        }
        return sb.ToString();
    }

    /// <summary>
    /// 语义检索个人记忆（按 user_id 过滤）
    /// </summary>
    private async Task<List<PersonalMemoryItem>> SearchPersonalMemoryAsync(long userId, string query, int limit)
    {
        var results = new List<PersonalMemoryItem>();
        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collection = _configuration["RAGSettings:QdrantMemoryCollection"] ?? "wms_personal_memory";
            var queryVector = await GenerateEmbeddingAsync(query);
            
            // 验证embedding是否正确生成
            if (queryVector == null || queryVector.Length == 0)
            {
                Console.WriteLine($"[Memory][Search] ⚠️ 警告：查询向量为空或长度为0，无法进行向量搜索");
                return results;
            }
            
            Console.WriteLine($"[Memory][Search] 查询向量维度: {queryVector.Length}, 前3个值: [{queryVector[0]}, {queryVector[1]}, {queryVector[2]}]");
            
            // 降低阈值或移除阈值限制，让更多相关结果通过
            var threshold = _configuration.GetValue<float>("RAGSettings:MemorySimilarityThreshold", 0.0f);
            Console.WriteLine($"[Memory][Search] 相似度阈值: {threshold}, 集合: {collection}, 用户ID: {userId}");

            var requestBody = new
            {
                vector = queryVector,
                limit = limit * 2, // 先获取更多结果，后续再筛选
                with_payload = true,
                score_threshold = threshold,
                filter = new
                {
                    must = new object[]
                    {
                        new { key = "user_id", match = new { value = userId } }
                    }
                }
            };

            var json = JsonSerializer.Serialize(requestBody);
            Console.WriteLine($"[Memory][Search] 请求URL: {qdrantUrl}/collections/{collection}/points/search");
            Console.WriteLine($"[Memory][Search] 请求体: {Truncate(json, 500)}");
            
            using var httpClient = new HttpClient();
            httpClient.Timeout = TimeSpan.FromSeconds(30);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            var resp = await httpClient.PostAsync($"{qdrantUrl}/collections/{collection}/points/search", content);
            
            if (!resp.IsSuccessStatusCode)
            {
                var errorContent = await resp.Content.ReadAsStringAsync();
                Console.WriteLine($"[Memory][Search] ⚠️ Qdrant API错误: {resp.StatusCode}, {errorContent}");
                return results;
            }
            
            resp.EnsureSuccessStatusCode();

            var responseContent = await resp.Content.ReadAsStringAsync();
            Console.WriteLine($"[Memory][Search] Qdrant响应长度: {responseContent.Length}");
            Console.WriteLine($"[Memory][Search] Qdrant响应前500字符: {Truncate(responseContent, 500)}");
            
            // 使用JsonDocument灵活解析，因为Payload可能是JsonElement
            // 重要：必须在JsonDocument dispose之前提取所有数据
            try
            {
                using var doc = JsonDocument.Parse(responseContent);
                var root = doc.RootElement;
                
                if (root.TryGetProperty("result", out var resultElement) && resultElement.ValueKind == JsonValueKind.Array)
                {
                    var resultArray = resultElement;
                    var count = resultArray.GetArrayLength();
                    Console.WriteLine($"[Memory][Search] Qdrant返回结果数量: {count}");
                    
                    int successCount = 0;
                    int failCount = 0;
                    
                    // 在JsonDocument dispose之前处理所有结果
                    for (int i = 0; i < count; i++)
                    {
                        try
                        {
                            var item = resultArray[i];
                            
                            long id = 0;
                            float score = 0;
                            JsonElement payloadElement = default;
                            
                            if (item.TryGetProperty("id", out var idElement))
                            {
                                id = idElement.GetInt64();
                            }
                            
                            if (item.TryGetProperty("score", out var scoreElement))
                            {
                                score = (float)scoreElement.GetDouble();
                            }
                            
                            if (item.TryGetProperty("payload", out payloadElement))
                            {
                                // 在JsonDocument dispose之前提取payload数据
                                if (TryExtractPersonalPayload(payloadElement, out var payload))
                                {
                                    Console.WriteLine($"[Memory][Search] ✅ 成功提取: id={id}, score={score:F4}, content={Truncate(payload.content, 50)}, role={payload.role}");
                                    results.Add(new PersonalMemoryItem
                                    {
                                        Content = payload.content,
                                        Role = payload.role,
                                        ConversationId = payload.conversation_id,
                                        Score = score
                                    });
                                    successCount++;
                                }
                                else
                                {
                                    Console.WriteLine($"[Memory][Search] ⚠️ 提取失败: id={id}, payload无法解析");
                                    failCount++;
                                }
                            }
                            else
                            {
                                Console.WriteLine($"[Memory][Search] ⚠️ 结果中无payload字段: id={id}");
                                failCount++;
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"[Memory][Search] ⚠️ 处理第{i}条结果时异常: {ex.Message}");
                            failCount++;
                        }
                    }
                    
                    Console.WriteLine($"[Memory][Search] 处理完成: 成功={successCount}, 失败={failCount}, 最终结果数={results.Count}");
                }
                else
                {
                    Console.WriteLine($"[Memory][Search] ⚠️ 响应中无result字段或result不是数组");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[Memory][Search] ⚠️ JsonDocument解析失败: {ex.Message}");
                Console.WriteLine($"[Memory][Search] 异常堆栈: {ex.StackTrace}");
                
                // 回退到标准反序列化
                try
                {
                    var search = JsonSerializer.Deserialize<QdrantSearchResponseLike>(responseContent);
                    if (search?.Result != null && search.Result.Length > 0)
                    {
                        Console.WriteLine($"[Memory][Search] 使用标准反序列化，结果数量: {search.Result.Length}");
                        foreach (var r in search.Result)
                        {
                            try
                            {
                                if (TryExtractPersonalPayload(r.Payload, out var payload))
                                {
                                    results.Add(new PersonalMemoryItem
                                    {
                                        Content = payload.content,
                                        Role = payload.role,
                                        ConversationId = payload.conversation_id,
                                        Score = r.Score
                                    });
                                }
                            }
                            catch { }
                        }
                    }
                }
                catch (Exception ex2)
                {
                    Console.WriteLine($"[Memory][Search] ⚠️ 标准反序列化也失败: {ex2.Message}");
                }
            }

            // 增强检索策略：无论向量检索是否命中，都进行关键词匹配增强
            try
            {
                Console.WriteLine($"[Memory][Search] 向量检索命中 {results.Count} 条，启用关键词匹配增强");
                var fallbackYou = await ScrollUserMemoriesAsync(userId, 200); // 增加滚动数量
                if (fallbackYou != null && fallbackYou.Count > 0)
                {
                    // 提取查询关键词
                    var keyword = ExtractKeywordFromQuery(query);
                    var queryLower = query.ToLower();
                    
                    // 对所有记忆进行关键词匹配打分
                    var keywordRanked = fallbackYou
                        .Select(p => new { 
                            item = p, 
                            score = ScoreByContains(p.Content, keyword, queryLower, query)
                        })
                        .Where(x => x.score > 0.5f) // 只保留高分匹配
                        .OrderByDescending(x => x.score)
                        .Take(limit * 2)
                        .ToList();
                    
                    if (keywordRanked.Count > 0)
                    {
                        Console.WriteLine($"[Memory][Search] 关键词匹配命中 {keywordRanked.Count} 条");
                        
                        // 合并向量检索结果和关键词匹配结果，去重并按分数排序
                        var merged = new Dictionary<string, PersonalMemoryItem>();
                        
                        // 先加入向量检索结果
                        foreach (var r in results)
                        {
                            var key = $"{r.Content}_{r.Role}";
                            if (!merged.ContainsKey(key) || merged[key].Score < r.Score)
                            {
                                merged[key] = r;
                            }
                        }
                        
                        // 加入关键词匹配结果（如果向量检索没找到，或关键词分数更高）
                        foreach (var x in keywordRanked)
                        {
                            var key = $"{x.item.Content}_{x.item.Role}";
                            if (!merged.ContainsKey(key))
                            {
                                x.item.Score = x.score;
                                merged[key] = x.item;
                            }
                            else if (merged[key].Score < x.score)
                            {
                                // 如果关键词匹配分数更高，更新
                                x.item.Score = x.score;
                                merged[key] = x.item;
                            }
                        }
                        
                        // 重新排序并限制数量：优先选择能提取到具体内容的记忆
                        results = merged.Values
                            .OrderByDescending(r => 
                            {
                                // 第一优先级：能否提取到具体内容
                                var extracted = ExtractLikeFromSingleMessage(r.Content);
                                return extracted != null ? 10000 : 0; // 能提取到具体内容的记忆分数+10000
                            })
                            .ThenByDescending(r => r.Score) // 第二优先级：原始分数
                            .Take(limit)
                            .ToList();
                        
                        Console.WriteLine($"[Memory][Search] 合并后共 {results.Count} 条结果（已按具体内容优先排序）");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[Memory][Search] 关键词匹配增强失败: {ex.Message}");
            }
            
            // 最终过滤和排序：确保返回的结果优先包含具体内容
            if (results.Count > 0)
            {
                var originalCount = results.Count;
                // 先过滤掉无效记忆（只包含询问词的记忆）
                var excludeKeywords = new[] { "什么", "啥", "哪个", "哪些", "多少", "如何", "怎么", "怎样", "?", "？", "呢", "吗" };
                var filteredResults = results
                    .Where(r => 
                    {
                        var content = r.Content ?? "";
                        var contentTrimmed = content.Trim();
                        var isOnlyQuestion = excludeKeywords.Any(k => 
                            contentTrimmed == $"我喜欢{k}" ||
                            contentTrimmed == $"我喜欢{k}。" ||
                            contentTrimmed == $"我喜欢{k}！" ||
                            contentTrimmed == $"我喜欢{k}?" ||
                            contentTrimmed == $"我喜欢{k}？");
                        var hasConcreteContent = ExtractLikeFromSingleMessage(content) != null;
                        // 只保留：不是只包含询问词 或 能提取到具体内容
                        return !isOnlyQuestion || hasConcreteContent;
                    })
                    .ToList();
                
                if (filteredResults.Count > 0)
                {
                    // 重新排序：优先包含具体内容的记忆
                    results = filteredResults
                        .OrderByDescending(r => 
                        {
                            // 第一优先级：能否提取到具体内容（这是最关键的）
                            var extracted = ExtractLikeFromSingleMessage(r.Content);
                            return extracted != null ? 10000 : 0; // 能提取到具体内容的记忆分数+10000
                        })
                        .ThenByDescending(r => r.Score) // 第二优先级：原始分数
                        .Take(limit)
                        .ToList();
                    
                    var filteredOutCount = originalCount - filteredResults.Count;
                    if (filteredOutCount > 0)
                    {
                        Console.WriteLine($"[Memory][Search] 过滤无效记忆: 原始{originalCount}条 -> 过滤掉{filteredOutCount}条无效记忆 -> 保留{filteredResults.Count}条 -> 最终返回{results.Count}条");
                    }
                    else
                    {
                        Console.WriteLine($"[Memory][Search] 排序完成: {results.Count}条结果（优先显示包含具体内容的记忆）");
                    }
                }
                else
                {
                    Console.WriteLine($"[Memory][Search] ⚠️ 所有{originalCount}条结果都被过滤（都是无效记忆），返回空列表");
                    results = new List<PersonalMemoryItem>();
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"检索个人记忆失败: {ex.Message}");
        }
        return results;
    }

    private async Task<List<PersonalMemoryItem>> ScrollUserMemoriesAsync(long userId, int limit)
    {
        var list = new List<PersonalMemoryItem>();
        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collection = _configuration["RAGSettings:QdrantMemoryCollection"] ?? "wms_personal_memory";
            using var http = new HttpClient();
            var body = new
            {
                limit = limit,
                with_payload = true,
                filter = new
                {
                    must = new object[]
                    {
                        new { key = "user_id", match = new { value = userId } }
                    }
                }
            };
            var json = JsonSerializer.Serialize(body);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            var resp = await http.PostAsync($"{qdrantUrl}/collections/{collection}/points/scroll", content);
            resp.EnsureSuccessStatusCode();
            var response = await resp.Content.ReadAsStringAsync();
            var parsed = JsonSerializer.Deserialize<QdrantScrollResponseLike>(response);
            if (parsed?.Result?.Points != null)
            {
                foreach (var p in parsed.Result.Points)
                {
                    if (TryExtractPersonalPayload(p.Payload, out var payload))
                    {
                        list.Add(new PersonalMemoryItem
                        {
                            Content = payload.content,
                            Role = payload.role,
                            ConversationId = payload.conversation_id,
                            Score = 0
                        });
                    }
                }
            }
        }
        catch { }
        return list;
    }

    private float ScoreByContains(string content, string keyword, string queryLower, string queryOriginal)
    {
        if (string.IsNullOrEmpty(content)) return 0;
        var contentLower = content.ToLower();
        float score = 0;
        
        // 精确关键词匹配（最高分）- 例如"葡萄"、"龙族"
        if (!string.IsNullOrEmpty(keyword) && content.Contains(keyword)) score += 0.9f;
        
        // ====== 增强的语义理解匹配 ======
        
        // 1. 处理"我喜欢什么"、"我喜欢啥"、"我喜欢什么X" 等询问模式
        if (queryLower.Contains("我喜欢什么") || queryLower.Contains("我喜欢啥") || queryLower.Contains("我的喜好") || 
            queryLower.Contains("喜欢什么") || queryLower.Contains("喜欢啥"))
        {
            // 检查记忆内容是否只包含询问词（无效记忆）
            var excludeKeywords = new[] { "什么", "啥", "哪个", "哪些", "多少", "如何", "怎么", "怎样", "?", "？", "呢", "吗" };
            var contentTrimmed = content.Trim();
            var isOnlyQuestion = excludeKeywords.Any(k => 
                contentTrimmed == $"我喜欢{k}" ||
                contentTrimmed == $"我喜欢{k}。" ||
                contentTrimmed == $"我喜欢{k}！" ||
                contentTrimmed == $"我喜欢{k}?" ||
                contentTrimmed == $"我喜欢{k}？");
            
            // 如果能提取到具体的喜好对象，给予高分
            var extracted = ExtractLikeFromSingleMessage(content);
            if (extracted != null && !string.IsNullOrEmpty(extracted))
            {
                // 包含具体喜好对象，给予高分（如"我喜欢吃葡萄"、"我喜欢葡萄"）
                score += 1.5f; // 比无效记忆高很多
            }
            else if (isOnlyQuestion)
            {
                // 只包含询问词，给予负分（降低优先级）
                score -= 2.0f; // 大幅降低无效记忆的分数
            }
            else if (content.Contains("我喜欢"))
            {
                // 包含"我喜欢"但不是只包含询问词，给予中等分数
                score += 0.5f;
            }
        }
        
        // 2. 处理"X是我喜欢的Y"这种表达（语序不同）
        // 例如："龙族是我喜欢的动漫" 应该匹配 "我喜欢什么动漫"
        if (queryLower.Contains("喜欢什么") || queryLower.Contains("喜欢啥"))
        {
            // 提取查询中的类别关键词（如"动漫"、"吃"、"水果"）
            var categoryMatch = System.Text.RegularExpressions.Regex.Match(queryLower, "喜欢什么(.+)|喜欢啥(.+)");
            string category = null;
            if (categoryMatch.Success)
            {
                category = (categoryMatch.Groups[1].Value ?? categoryMatch.Groups[2].Value ?? "").Trim();
            }
            
            // 如果内容中包含"是我喜欢的"模式，提取前面的对象
            var reverseMatch = System.Text.RegularExpressions.Regex.Match(content, "(.{1,20})是我喜欢的(.{0,10})");
            if (reverseMatch.Success)
            {
                var objectName = reverseMatch.Groups[1].Value.Trim();
                var objectCategory = reverseMatch.Groups[2].Value.Trim();
                
                // 如果类别匹配，高分
                if (!string.IsNullOrEmpty(category) && (content.Contains(category) || objectCategory.Contains(category)))
                {
                    score += 1.2f; // 最高优先级
                }
                else if (string.IsNullOrEmpty(category))
                {
                    // 没有指定类别，只要包含"是我喜欢的"就给高分
                    score += 1.0f;
                }
            }
        }
        
        // 3. "我喜欢X"模式匹配（通用）
        if (content.Contains("我喜欢")) 
        {
            score += 0.6f;
            
            // 如果查询包含"喜欢什么"，更优先匹配"我喜欢"的记忆
            if (queryLower.Contains("喜欢什么") || queryLower.Contains("喜欢啥"))
            {
                score += 0.4f;
            }
        }
        
        if (content.Contains("喜欢") && !content.Contains("我喜欢")) score += 0.3f;
        
        // 4. 处理"我喜欢吃什么"、"我喜欢什么X"等带类别的查询
        // 例如："我喜欢吃什么" 应该匹配 "我喜欢葡萄"（葡萄是食物）
        if (queryLower.Contains("喜欢吃什么") || queryLower.Contains("喜欢吃什么"))
        {
            // 食物相关关键词
            var foodKeywords = new[] { "吃", "食物", "水果", "蔬菜", "菜", "饭", "零食" };
            var hasFoodKeyword = foodKeywords.Any(k => content.Contains(k));
            
            if (content.Contains("我喜欢") && (hasFoodKeyword || !string.IsNullOrEmpty(keyword)))
            {
                score += 0.7f;
            }
        }
        
        if (queryLower.Contains("喜欢什么动漫") || queryLower.Contains("喜欢什么动画"))
        {
            var animeKeywords = new[] { "动漫", "动画", "番", "剧" };
            var hasAnimeKeyword = animeKeywords.Any(k => content.Contains(k));
            
            if ((content.Contains("我喜欢") || content.Contains("是我喜欢的")) && hasAnimeKeyword)
            {
                score += 0.7f;
            }
        }
        
        // 5. 查询内容部分匹配
        if (!string.IsNullOrEmpty(queryLower) && contentLower.Contains(queryLower)) score += 0.3f;
        if (!string.IsNullOrEmpty(queryOriginal) && content.Contains(queryOriginal)) score += 0.2f;
        
        // 6. "什么/啥" 等询问词，优先匹配包含"我喜欢"的记忆
        if (queryLower.Contains("什么") || queryLower.Contains("啥"))
        {
            if (content.Contains("我喜欢") || content.Contains("是我喜欢的"))
            {
                score += 0.5f;
            }
        }
        
        return score;
    }

    private string ExtractKeywordFromQuery(string query)
    {
        if (string.IsNullOrWhiteSpace(query)) return null;
        var queryLower = query.ToLower();
        
        // 1. 提取"我喜欢X"模式中的X
        var m1 = System.Text.RegularExpressions.Regex.Match(query, "我喜欢(?<x>.{1,20})");
        if (m1.Success)
        {
            var extracted = m1.Groups["x"].Value.Trim();
            // 过滤掉询问词
            var excludeWords = new[] { "什么", "啥", "哪个", "哪些", "多少", "如何", "怎么", "怎样", "?", "？", "呢", "吗", "的" };
            if (!excludeWords.Any(w => extracted.Contains(w)))
            {
                return extracted;
            }
        }
        
        // 2. 提取"X是我喜欢的Y"模式中的X（语序不同）
        var m2 = System.Text.RegularExpressions.Regex.Match(query, "(.{1,20})是我喜欢的(.{0,10})");
        if (m2.Success)
        {
            return m2.Groups[1].Value.Trim();
        }
        
        // 3. 提取"我喜欢吃什么"中的关键词（如果记忆中有具体食物名称）
        // 这里返回null，让ScoreByContains通过语义匹配处理
        
        // 4. 如果没有匹配到模式，尝试提取名词性词语（简单版）
        // 移除常见询问词和动词
        var cleaned = query
            .Replace("我喜欢", "")
            .Replace("喜欢什么", "")
            .Replace("喜欢啥", "")
            .Replace("什么", "")
            .Replace("啥", "")
            .Replace("的", "")
            .Trim();
        
        if (!string.IsNullOrWhiteSpace(cleaned) && cleaned.Length <= 20)
        {
            return cleaned;
        }
        
        return null;
    }

    /// <summary>
    /// 构建个人记忆系统提示片段
    /// </summary>
    private async Task<string> BuildPersonalMemoryContextAsync(long userId, string query)
    {
        if (!_configuration.GetValue<bool>("RAGSettings:EnablePersonalMemory", true))
        {
            return string.Empty;
        }
        var maxK = _configuration.GetValue<int>("RAGSettings:MaxMemoryResults", 5);
        var memories = await SearchPersonalMemoryAsync(userId, query, maxK);
        try
        {
            Console.WriteLine($"[Memory][Search] userId={userId}, query={Truncate(query, 120)}, hits={memories?.Count ?? 0}");
            if (memories != null && memories.Count > 0)
            {
                Console.WriteLine($"[Memory][Search] ✅ 成功检索到 {memories.Count} 条个人记忆（显示前{Math.Min(5, memories.Count)}条）：");
                // 只显示前5条，避免日志过多，并显示是否能提取到具体内容
                int memoryIdx = 1;
                foreach (var m in memories.Take(5))
                {
                    var extracted = ExtractLikeFromSingleMessage(m.Content);
                    var extractedInfo = extracted != null ? $", ✅提取={extracted}" : ", ❌无具体内容";
                    Console.WriteLine($"  #{memoryIdx++} score={m.Score:F3} role={m.Role} content={Truncate(m.Content, 80)}{extractedInfo}");
                }
                if (memories.Count > 5)
                {
                    Console.WriteLine($"  ... 还有 {memories.Count - 5} 条记忆未显示");
                }
            }
            else
            {
                Console.WriteLine("[Memory][Search] ⚠️ 向量检索未命中，尝试从数据库对话历史提取");
                // 最终兜底：从数据库对话历史中提取相关信息
                var historyMemories = await ExtractMemoriesFromConversationHistoryAsync(userId, query);
                if (historyMemories != null && historyMemories.Count > 0)
                {
                    Console.WriteLine($"[Memory][Search] ✅ 从对话历史提取到 {historyMemories.Count} 条相关记忆");
                    memories = historyMemories;
                    // 打印提取到的记忆
                    int historyIdx = 1;
                    foreach (var m in historyMemories.Take(maxK))
                    {
                        Console.WriteLine($"  #{historyIdx++} score={m.Score:F3} content={Truncate(m.Content, 200)}");
                    }
                }
                else
                {
                    Console.WriteLine("[Memory][Search] ❌ 所有检索方案都未命中，个人记忆为空");
                }
            }
        }
        catch { }
        if (memories == null || memories.Count == 0)
        {
            return string.Empty;
        }
        
        // 过滤无效记忆：排除只包含询问词的记忆（如"我喜欢什么"）
        var excludeKeywords = new[] { "什么", "啥", "哪个", "哪些", "多少", "如何", "怎么", "怎样", "?", "？", "呢", "吗" };
        var validMemories = memories
            .Where(m => 
            {
                var content = m.Content ?? "";
                var contentTrimmed = content.Trim();
                
                // 检查是否是只包含询问词的记忆（如"我喜欢什么"、"我喜欢啥"等）
                var isOnlyQuestion = excludeKeywords.Any(k => 
                    contentTrimmed == $"我喜欢{k}" ||
                    contentTrimmed == $"我喜欢{k}。" ||
                    contentTrimmed == $"我喜欢{k}！" ||
                    contentTrimmed == $"我喜欢{k}?" ||
                    contentTrimmed == $"我喜欢{k}？" ||
                    contentTrimmed.Contains($"我喜欢{k}") && ExtractLikeFromSingleMessage(content) == null);
                
                // 如果能提取到具体的喜好对象，则认为是有效记忆
                var hasConcreteContent = ExtractLikeFromSingleMessage(content) != null;
                
                // 保留：1) 不是只包含询问词 或 2) 能提取到具体喜好对象
                return !isOnlyQuestion || hasConcreteContent;
            })
            .OrderByDescending(m => 
            {
                // 第一优先级：能否提取到具体喜好对象（这是最关键的）
                var extracted = ExtractLikeFromSingleMessage(m.Content);
                return extracted != null ? 1000 : 0; // 能提取到具体内容的记忆分数+1000
            })
            .ThenByDescending(m => m.Score) // 第二优先级：原始分数
            .Take(maxK)
            .ToList();
        
        if (validMemories.Count == 0)
        {
            return string.Empty;
        }
        
        var sb = new StringBuilder();
        sb.AppendLine("=== 【重要】用户个人记忆（必须使用） ===");
        sb.AppendLine();
        sb.AppendLine("以下是从向量数据库中检索到的用户个人记忆，这些是用户之前明确表达过的偏好、喜好或习惯：");
        sb.AppendLine();
        
        // 优先展示包含具体喜好对象的记忆（【核心记忆】）
        var concreteMemories = validMemories
            .Where(m => ExtractLikeFromSingleMessage(m.Content) != null)
            .ToList();
        
        int idx = 1;
        if (concreteMemories.Count > 0)
        {
            sb.AppendLine("【核心记忆】（必须优先使用，这是唯一需要关注的部分）：");
            foreach (var m in concreteMemories)
            {
                var role = m.Role == "user" ? "【用户说】" : "【小智说】";
                var extracted = ExtractLikeFromSingleMessage(m.Content);
                sb.AppendLine($"{idx++}. {role} {m.Content} (相关度: {m.Score:F2}, 提取内容: {extracted})");
            }
            sb.AppendLine();
            sb.AppendLine("⚠️⚠️⚠️ 重要：上述【核心记忆】包含具体的喜好对象，必须直接使用这些内容回答！");
            sb.AppendLine();
        }
        
        // 其他相关记忆（仅在偏好查询且没有【核心记忆】时显示，且进一步过滤无效记忆）
        var otherMemories = validMemories
            .Where(m => 
            {
                // 只包含询问词的记忆不算"其他相关记忆"
                var content = m.Content ?? "";
                var excludeKeywords = new[] { "什么", "啥", "哪个", "哪些", "多少", "如何", "怎么", "怎样", "?", "？", "呢", "吗" };
                var isOnlyQuestion = excludeKeywords.Any(k => 
                    content.Trim() == $"我喜欢{k}" ||
                    content.Trim() == $"我喜欢{k}。" ||
                    content.Trim() == $"我喜欢{k}！" ||
                    content.Trim() == $"我喜欢{k}?" ||
                    content.Trim() == $"我喜欢{k}？");
                
                return ExtractLikeFromSingleMessage(m.Content) == null && !isOnlyQuestion;
            })
            .ToList();
        
        // 如果有【核心记忆】，就不显示"其他相关记忆"（避免干扰）
        if (concreteMemories.Count == 0 && otherMemories.Count > 0)
        {
            sb.AppendLine("【其他相关记忆】（仅供参考）：");
            foreach (var m in otherMemories)
            {
                var role = m.Role == "user" ? "【用户说】" : "【小智说】";
                sb.AppendLine($"{idx++}. {role} {m.Content} (相关度: {m.Score:F2})");
            }
            sb.AppendLine();
        }
        
        sb.AppendLine();
        sb.AppendLine("🚨🚨🚨【关键提示】🚨🚨🚨：");
        sb.AppendLine("当用户询问\"我喜欢什么\"、\"我喜欢吃什么\"、\"我喜欢什么动漫\"等偏好问题时，");
        sb.AppendLine("必须从上面的【核心记忆】部分提取具体的喜好对象，直接回答，绝对不要反问或猜测！");
        sb.AppendLine();
        sb.AppendLine("【提取规则】（严格按照以下规则）：");
        sb.AppendLine("- \"我喜欢葡萄\" → 提取\"葡萄\" → 回答\"你喜欢葡萄哦~ 😊\"");
        sb.AppendLine("- \"龙族是我喜欢的动漫\" → 提取\"龙族\" → 回答\"你喜欢《龙族》这部动漫哦~ 😊\"");
        sb.AppendLine("- \"我喜欢吃葡萄\" → 提取\"葡萄\" → 回答\"你喜欢吃葡萄哦~ 😊\"或\"你喜欢葡萄哦~ 😊\"");
        sb.AppendLine();
        sb.AppendLine("⚠️⚠️⚠️【严格禁止】⚠️⚠️⚠️：");
        sb.AppendLine("- 禁止说\"虽然现在还不清楚你喜欢什么\"");
        sb.AppendLine("- 禁止反问\"你想不起来了吗\"、\"让我猜猜\"");
        sb.AppendLine("- 禁止给出通用的建议或列表");
        sb.AppendLine("- 禁止说\"我没有相关记忆\"或\"让我查看一下\"");
        sb.AppendLine("- 必须使用【核心记忆】中的具体内容，直接回答！");
        sb.AppendLine();
        return sb.ToString();
    }

    /// <summary>
    /// 从数据库对话历史中提取个人记忆（最终兜底方案）
    /// </summary>
    private async Task<List<PersonalMemoryItem>> ExtractMemoriesFromConversationHistoryAsync(long userId, string query)
    {
        var results = new List<PersonalMemoryItem>();
        try
        {
            Console.WriteLine($"[Memory] 开始从数据库对话历史提取，userId={userId}, query={Truncate(query, 100)}");
            
            // 获取用户最近的对话记录（按 userId 和对话时间倒序）
            var recentMessages = await _messageRepo.GetListAsync(m => m.UserId == userId || (m.UserId == 0 && !m.IsFromUser));
            Console.WriteLine($"[Memory] 找到 {recentMessages.Count} 条消息");
            var userMessages = recentMessages
                .Where(m => m.IsFromUser && !string.IsNullOrEmpty(m.Message))
                .OrderByDescending(m => m.Timestamp)
                .Take(50)
                .ToList();

            if (userMessages.Count == 0) return results;

            var queryLower = query.ToLower();
            var keyword = ExtractKeywordFromQuery(query);

            // 对每条消息打分（降低分数阈值，确保相关记忆能被检索到）
            var scored = userMessages
                .Select(m => new
                {
                    message = m,
                    score = ScoreByContains(m.Message, keyword, queryLower, query)
                })
                .Where(x => x.score > 0.3f) // 降低阈值，从 0 改为 0.3，过滤掉完全不相关的
                .OrderByDescending(x => x.score)
                .Take(10)
                .ToList();

            // 过滤无效记忆：排除只包含询问词的记忆
            var excludeKeywords = new[] { "什么", "啥", "哪个", "哪些", "多少", "如何", "怎么", "怎样", "?", "？", "呢", "吗" };
            
            foreach (var item in scored)
            {
                var content = item.message.Message ?? "";
                // 排除只包含"我喜欢什么"、"我喜欢啥"等询问的记忆
                var isOnlyQuestion = excludeKeywords.Any(k => 
                    content.Contains($"我喜欢{k}") || 
                    content.Trim() == "我喜欢什么" ||
                    content.Trim() == "我喜欢啥");
                
                // 如果记忆只包含询问词，但提取不到具体喜好对象，则跳过
                if (isOnlyQuestion && ExtractLikeFromSingleMessage(content) == null)
                {
                    Console.WriteLine($"[Memory] 过滤无效记忆: {Truncate(content, 50)} (只包含询问词)");
                    continue;
                }
                
                results.Add(new PersonalMemoryItem
                {
                    Content = content,
                    Role = "user",
                    ConversationId = item.message.ConversationId,
                    Score = item.score
                });
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"[Memory] 从对话历史提取失败: {ex.Message}");
        }
        return results;
    }

    /// <summary>
    /// 基于数据分析生成库存回复
    /// </summary>
    private async Task<string> GenerateInventoryResponseWithData(string userMessage, string context, string dataAnalysis)
    {
        await Task.CompletedTask;
        
        return $@"你好呀~ 根据刚才的实时数据分析报告，我看到：

{dataAnalysis}

基于这些数据，我建议你：
- 📊 定期检查库存预警设置，确保及时补货
- 🔍 关注高频出入库商品，优化库存结构
- 📈 分析库存周转率，提高资金使用效率
- ⚠️ 及时处理积压库存，避免资金占用

有什么具体的库存问题需要我帮你分析吗？😊";
    }

    /// <summary>
    /// 基于数据分析生成订单回复
    /// </summary>
    private async Task<string> GenerateOrderResponseWithData(string userMessage, string context, string dataAnalysis)
    {
        await Task.CompletedTask;
        
        return $@"你好呀~ 根据刚才的实时数据分析报告，我看到：

{dataAnalysis}

基于这些数据，我建议你：
- 📋 优先处理待审核订单，提高客户满意度
- ⏰ 关注订单处理时效，优化业务流程
- 📊 定期分析订单趋势，预测业务需求
- 🎯 重点关注大客户订单，维护客户关系

需要我帮你查看具体的订单详情吗？✨";
    }

    /// <summary>
    /// 基于数据分析生成客户回复
    /// </summary>
    private async Task<string> GenerateCustomerResponseWithData(string userMessage, string context, string dataAnalysis)
    {
        await Task.CompletedTask;
        
        return $@"你好呀~ 根据刚才的实时数据分析报告，我看到：

{dataAnalysis}

基于这些数据，我建议你：
- 👥 维护客户关系管理，提高客户忠诚度
- 📞 关注客户满意度，及时处理客户反馈
- 🔄 定期客户回访，了解客户需求变化
- 📈 分析客户价值，制定差异化服务策略

有什么客户管理方面的问题需要我帮你解决吗？🎯";
    }

    /// <summary>
    /// 基于数据分析生成仓库回复
    /// </summary>
    private async Task<string> GenerateWarehouseResponseWithData(string userMessage, string context, string dataAnalysis)
    {
        await Task.CompletedTask;
        
        return $@"你好呀~ 根据刚才的实时数据分析报告，我看到：

{dataAnalysis}

基于这些数据，我建议你：
- 🏭 定期进行仓库盘点，确保数据准确性
- 📐 优化仓库布局，提高作业效率
- 🔧 加强设备维护，减少故障停机
- 📊 分析仓库利用率，合理规划空间

需要我帮你制定仓库管理优化方案吗？💡";
    }

    /// <summary>
    /// 基于数据分析生成帮助回复
    /// </summary>
    private async Task<string> GenerateHelpResponseWithData(string userMessage, string context, string dataAnalysis)
    {
        await Task.CompletedTask;
        
        return $@"你好呀~ 根据刚才的实时数据分析报告，我看到：

{dataAnalysis}

基于这些数据，我建议你：
- 📚 学习WMS系统操作，提高工作效率
- 🔧 定期系统维护，确保稳定运行
- 📊 关注系统性能指标，及时优化
- 🆘 遇到问题及时联系技术支持

我是你的专属WMS智能助手小智，有什么问题随时问我哦！🚀";
    }

    /// <summary>
    /// 基于数据分析生成错误回复
    /// </summary>
    private async Task<string> GenerateErrorResponseWithData(string userMessage, string context, string dataAnalysis)
    {
        await Task.CompletedTask;
        
        return $@"你好呀~ 根据刚才的实时数据分析报告，我看到：

{dataAnalysis}

基于这些数据，我建议你：
- 🔍 详细记录错误信息，便于问题定位
- 📸 提供错误截图，帮助快速诊断
- 📝 描述操作步骤，重现问题场景
- 🆘 及时联系技术支持，获得专业帮助

别担心，我会帮你解决这个问题的！😊";
    }

    /// <summary>
    /// 基于数据分析生成通用回复
    /// </summary>
    private async Task<string> GenerateGeneralResponseWithData(string userMessage, string context, string dataAnalysis)
    {
        await Task.CompletedTask;
        
        return $@"你好呀~ 根据刚才的实时数据分析报告，我看到：

{dataAnalysis}

基于这些数据，我建议你：
- 📊 定期备份重要数据，确保数据安全
- 🔧 关注系统性能指标，及时优化
- ⚠️ 及时处理系统告警，预防问题发生
- 📈 分析业务趋势，制定改进策略

我是你的专属WMS智能助手小智，有什么问题随时问我哦！✨";
    }

    /// <summary>
    /// 初始化示例知识库数据
    /// </summary>
    private async Task InitializeSampleKnowledge()
    {
        try
        {
            // 等待数据库连接稳定
            await Task.Delay(2000);
            
            // 检查是否已有知识库数据
            var existingCount = await _knowledgeRepo.CountAsync(k => k.Id > 0);
            if (existingCount > 0)
            {
                Console.WriteLine($"知识库已有 {existingCount} 条数据，跳过初始化");
                return;
            }

            Console.WriteLine("开始初始化示例知识库数据...");

            var sampleData = new[]
            {
                new Admin.NET.Application.Entity.KnowledgeBase
                {
                    Title = "WMS库存管理基础",
                    Category = "inventory_query",
                    Keywords = "库存,管理,查询,SKU,商品",
                    Content = "WMS库存管理是仓库管理系统的核心功能。主要包含：1. 实时库存查询 - 支持按SKU、商品名称、仓库位置查询；2. 库存预警 - 当库存低于安全库存时自动提醒；3. 库存盘点 - 定期进行库存盘点确保数据准确性；4. 库存调拨 - 支持仓库间库存调拨操作。",
                    Source = "系统内置",
                    DocumentType = "text",
                    Priority = 1,
                    IsEnabled = true,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now
                },
                new Admin.NET.Application.Entity.KnowledgeBase
                {
                    Title = "订单状态查询指南",
                    Category = "order_query",
                    Keywords = "订单,状态,查询,进度,单号",
                    Content = "订单状态查询功能说明：1. 销售订单状态包括：草稿、待审核、已审核、未出库、已完成、已关闭；2. 采购订单状态包括：草稿、待审核、已审核、未入库、已完成、已关闭；3. 查询方式：支持按订单号、客户名称、时间范围查询；4. 订单进度跟踪：可查看订单的详细处理进度和预计完成时间。",
                    Source = "系统内置",
                    DocumentType = "text",
                    Priority = 1,
                    IsEnabled = true,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now
                },
                new Admin.NET.Application.Entity.KnowledgeBase
                {
                    Title = "仓库操作流程",
                    Category = "warehouse_operation",
                    Keywords = "仓库,操作,入库,出库,调拨,盘点",
                    Content = "仓库操作标准流程：1. 入库操作：接收货物→验货→入库登记→更新库存；2. 出库操作：订单确认→拣货→验货→出库登记→更新库存；3. 调拨操作：申请调拨→审核→执行调拨→更新双方库存；4. 盘点操作：制定盘点计划→执行盘点→差异分析→库存调整。",
                    Source = "系统内置",
                    DocumentType = "text",
                    Priority = 1,
                    IsEnabled = true,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now
                },
                new Admin.NET.Application.Entity.KnowledgeBase
                {
                    Title = "系统故障排除",
                    Category = "error_report",
                    Keywords = "故障,错误,问题,排除,解决",
                    Content = "常见系统故障及解决方案：1. 登录问题：检查用户名密码、网络连接、浏览器兼容性；2. 数据加载慢：检查网络状况、清理浏览器缓存、重启系统；3. 打印问题：检查打印机连接、驱动安装、纸张设置；4. 数据异常：联系技术支持、提供错误截图、描述操作步骤。",
                    Source = "系统内置",
                    DocumentType = "text",
                    Priority = 1,
                    IsEnabled = true,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now
                },
                new Admin.NET.Application.Entity.KnowledgeBase
                {
                    Title = "WMS系统功能介绍",
                    Category = "system_help",
                    Keywords = "系统,功能,介绍,帮助,使用",
                    Content = "WMS系统主要功能模块：1. 库存管理 - 实时库存查询、库存预警、盘点管理；2. 订单管理 - 销售订单、采购订单、订单跟踪；3. 仓库管理 - 仓库信息、货位管理、操作记录；4. 客户管理 - 客户信息、联系方式、合作历史；5. 报表分析 - 库存报表、订单报表、运营分析。",
                    Source = "系统内置",
                    DocumentType = "text",
                    Priority = 1,
                    IsEnabled = true,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now
                }
            };

            foreach (var knowledge in sampleData)
            {
                await RetryDatabaseOperation(async () => await _knowledgeRepo.InsertAsync(knowledge));
            }

            Console.WriteLine($"成功初始化 {sampleData.Length} 条示例知识库数据");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"初始化示例知识库数据失败: {ex.Message}");
        }
    }
    private async Task<string> GenerateFallbackResponse(string userMessage, string context, UserIntent intent)
    {
        // 使用原有的模板回复作为备用
        switch (intent.Type)
        {
            case "inventory_query":
                return await GenerateInventoryResponse(userMessage, context);
            case "order_query":
                return await GenerateOrderResponse(userMessage, context);
            case "warehouse_operation":
                return await GenerateWarehouseResponse(userMessage, context);
            case "system_help":
                return await GenerateHelpResponse(userMessage, context);
            case "error_report":
                return await GenerateErrorResponse(userMessage, context);
            default:
                return await GenerateGeneralResponse(userMessage, context);
        }
    }

    /// <summary>
    /// 生成库存查询回复
    /// </summary>
    private async Task<string> GenerateInventoryResponse(string userMessage, string context)
    {
        await Task.CompletedTask; // 避免async警告
        
        // 提取SKU或商品信息
        var skuMatch = System.Text.RegularExpressions.Regex.Match(userMessage, @"[A-Za-z0-9\-_]+");
        var sku = skuMatch.Success ? skuMatch.Value : "";
        
        if (!string.IsNullOrEmpty(sku))
        {
            try
            {
                // 调用实际的库存查询API
                var inventoryData = await QueryInventoryBySku(sku);
                if (inventoryData != null)
                {
                    return $"📦 **库存查询结果**\n\n" +
                           $"**商品编码**: {sku}\n" +
                           $"**商品名称**: {inventoryData.GoodsName}\n" +
                           $"**当前库存**: {inventoryData.StockQuantity} 件\n" +
                           $"**可用库存**: {inventoryData.AvailableQuantity} 件\n" +
                           $"**仓库位置**: {inventoryData.WarehouseName}\n\n" +
                           $"数据更新时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
                }
                else
                {
                    return $"❌ 未找到商品编码为 {sku} 的库存信息。\n\n" +
                           "请检查商品编码是否正确，或提供商品名称进行查询。";
                }
            }
            catch (Exception ex)
            {
                return $"⚠️ 查询库存时出现错误：{ex.Message}\n\n" +
                       "请稍后重试或联系技术支持。";
            }
        }
        
        return "🔍 **库存查询服务**\n\n" +
               "我可以帮您查询商品库存信息。请提供以下信息：\n\n" +
               "• **商品编码（SKU）**：如 SKU-123、ABC-456\n" +
               "• **商品名称**：如 苹果手机、笔记本电脑\n\n" +
               "**示例**：\n" +
               "• \"查询SKU-123的库存\"\n" +
               "• \"苹果手机还有多少库存？\"\n" +
               "• \"笔记本电脑的库存情况\"";
    }

    /// <summary>
    /// 根据SKU查询库存信息
    /// </summary>
    private async Task<dynamic> QueryInventoryBySku(string sku)
    {
        try
        {
            // 查询商品信息
            var goods = await _salesOrderRepo.GetFirstAsync(g => g.GoodsName.Contains(sku));
            if (goods == null)
            {
                return null;
            }

            // 模拟库存数据（实际项目中应该从库存表查询）
            return new
            {
                GoodsName = goods.GoodsName ?? "未知商品",
                StockQuantity = new Random().Next(10, 100),
                AvailableQuantity = new Random().Next(5, 50),
                WarehouseName = "主仓库"
            };
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// 生成订单查询回复
    /// </summary>
    private async Task<string> GenerateOrderResponse(string userMessage, string context)
    {
        await Task.CompletedTask; // 避免async警告
        
        var orderMatch = System.Text.RegularExpressions.Regex.Match(userMessage, @"[A-Za-z0-9\-_]{6,}");
        var orderCode = orderMatch.Success ? orderMatch.Value : "";
        
        if (!string.IsNullOrEmpty(orderCode))
        {
            try
            {
                // 查询订单信息
                var orderData = await QueryOrderByCode(orderCode);
                if (orderData != null)
                {
                    return $"📋 **订单查询结果**\n\n" +
                           $"**订单编号**: {orderCode}\n" +
                           $"**订单状态**: {orderData.Status}\n" +
                           $"**客户名称**: {orderData.CustomerName}\n" +
                           $"**订单金额**: ¥{orderData.TotalAmount:N2}\n" +
                           $"**创建时间**: {orderData.CreateTime:yyyy-MM-dd HH:mm:ss}\n" +
                           $"**预计完成**: {orderData.ExpectedDate:yyyy-MM-dd}\n\n" +
                           $"💡 **订单进度**: {GetOrderProgressDescription(orderData.Status)}";
                }
                else
                {
                    return $"❌ 未找到订单编号为 {orderCode} 的订单信息。\n\n" +
                           "请检查订单编号是否正确，或联系客服人员协助查询。";
                }
            }
            catch (Exception ex)
            {
                return $"⚠️ 查询订单时出现错误：{ex.Message}\n\n" +
                       "请稍后重试或联系技术支持。";
            }
        }
        
        return "📋 **订单查询服务**\n\n" +
               "我可以帮您查询订单状态和详细信息。请提供订单编号：\n\n" +
               "**支持的订单类型**：\n" +
               "• 销售订单（SO开头）\n" +
               "• 采购订单（PO开头）\n" +
               "• 入库单（IN开头）\n" +
               "• 出库单（OUT开头）\n\n" +
               "**示例**：\n" +
               "• \"查询订单SO20240101001\"\n" +
               "• \"PO20240101002的状态\"\n" +
               "• \"IN20240101003的进度\"";
    }

    /// <summary>
    /// 根据订单编号查询订单信息
    /// </summary>
    private async Task<dynamic> QueryOrderByCode(string orderCode)
    {
        try
        {
            // 查询销售订单
            var salesOrder = await _salesOrderRepo.GetFirstAsync(o => o.Code == orderCode);
            if (salesOrder != null)
            {
                return new
                {
                    Status = GetOrderStatusText(salesOrder.DocumentStatus),
                    CustomerName = salesOrder.CustomerName ?? "未知客户",
                    TotalAmount = salesOrder.SalesAmount,
                    CreateTime = salesOrder.CreateTime,
                    ExpectedDate = salesOrder.CreateTime.AddDays(7)
                };
            }

            // 查询采购订单
            var purchaseOrder = await _purchaseOrderRepo.GetFirstAsync(o => o.Code == orderCode);
            if (purchaseOrder != null)
            {
                return new
                {
                    Status = GetOrderStatusText(purchaseOrder.DocumentStatus),
                    CustomerName = purchaseOrder.Supplier ?? "未知供应商",
                    TotalAmount = purchaseOrder.ItemAmount,
                    CreateTime = purchaseOrder.CreateTime,
                    ExpectedDate = purchaseOrder.CreateTime.AddDays(5)
                };
            }

            return null;
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// 获取订单状态文本
    /// </summary>
    private string GetOrderStatusText(object status)
    {
        if (status is DocumentStatusEnum enumStatus)
        {
            return enumStatus switch
            {
                DocumentStatusEnum.Draft => "草稿",
                DocumentStatusEnum.PendingReview => "待审核",
                DocumentStatusEnum.Rejected => "驳回",
                DocumentStatusEnum.NotOutOfWarehouse => "未出库",
                DocumentStatusEnum.Completed => "已完成",
                DocumentStatusEnum.Closed => "已关闭",
                _ => "未知状态"
            };
        }
        else if (status is string stringStatus)
        {
            return stringStatus switch
            {
                "Draft" => "草稿",
                "Pending" => "待处理",
                "Processing" => "处理中",
                "Completed" => "已完成",
                "Cancelled" => "已取消",
                _ => stringStatus
            };
        }
        
        return "未知状态";
    }

    /// <summary>
    /// 获取订单进度描述
    /// </summary>
    private string GetOrderProgressDescription(string status)
    {
        return status switch
        {
            "待处理" => "订单已创建，等待系统处理",
            "处理中" => "订单正在处理中，预计很快完成",
            "已完成" => "订单已成功完成",
            "已取消" => "订单已被取消",
            _ => "订单状态异常，请联系客服"
        };
    }

    /// <summary>
    /// 生成仓库操作回复
    /// </summary>
    private async Task<string> GenerateWarehouseResponse(string userMessage, string context)
    {
        await Task.CompletedTask; // 避免async警告
        
        return "我可以为您提供仓库操作指导，包括：\n\n" +
               "• 入库操作：商品入库的详细步骤\n" +
               "• 出库操作：商品出库的操作流程\n" +
               "• 调拨操作：仓库间商品调拨\n" +
               "• 盘点操作：库存盘点的操作指南\n\n" +
               "请告诉我您需要了解哪种操作的具体步骤？";
    }

    /// <summary>
    /// 生成帮助回复
    /// </summary>
    private async Task<string> GenerateHelpResponse(string userMessage, string context)
    {
        await Task.CompletedTask; // 避免async警告
        
        return "我是您的WMS智能客服助手，可以为您提供以下帮助：\n\n" +
               "🔍 **库存查询**：查询商品库存数量和状态\n" +
               "📋 **订单管理**：查询订单状态和处理进度\n" +
               "🏪 **仓库操作**：指导入库、出库、调拨等操作\n" +
               "❓ **问题解答**：解答系统使用中的常见问题\n" +
               "🎫 **工单创建**：为复杂问题创建技术支持工单\n\n" +
               "请告诉我您需要什么帮助？";
    }

    /// <summary>
    /// 生成错误处理回复
    /// </summary>
    private async Task<string> GenerateErrorResponse(string userMessage, string context)
    {
        await Task.CompletedTask; // 避免async警告
        
        return "我理解您遇到了问题。为了更好地帮助您解决，请提供以下信息：\n\n" +
               "• 具体的错误信息或现象\n" +
               "• 出现问题的操作步骤\n" +
               "• 使用的浏览器或设备信息\n\n" +
               "根据您提供的信息，我将为您提供解决方案，或为您创建技术支持工单。";
    }

    /// <summary>
    /// 生成通用回复
    /// </summary>
    private async Task<string> GenerateGeneralResponse(string userMessage, string context)
    {
        await Task.CompletedTask; // 避免async警告
        
        return "我理解您的问题。基于我的知识库，我为您提供以下建议：\n\n" +
               "如果您需要更具体的帮助，请告诉我：\n" +
               "• 您遇到的具体问题\n" +
               "• 您想要了解的操作\n" +
               "• 您需要查询的信息\n\n" +
               "我将为您提供详细的指导和帮助。";
    }

    /// <summary>
    /// 生成操作建议
    /// </summary>
    private async Task<List<CustomerServiceAction>> GenerateActions(UserIntent intent, List<Admin.NET.Application.Entity.KnowledgeBase> knowledge)
    {
        await Task.CompletedTask; // 避免async警告
        
        var actions = new List<CustomerServiceAction>();
        
        switch (intent.Type)
        {
            case "inventory_query":
                actions.Add(new CustomerServiceAction { Type = "query_inventory", Data = intent.Entities });
                break;
            case "order_query":
                actions.Add(new CustomerServiceAction { Type = "query_order", Data = intent.Entities });
                break;
            case "error_report":
                actions.Add(new CustomerServiceAction { Type = "create_work_order", Data = new { category = "error" } });
                break;
        }
        
        return actions;
    }

    /// <summary>
    /// 提取实体信息
    /// </summary>
    private Dictionary<string, string> ExtractEntities(string message, string intentType)
    {
        var entities = new Dictionary<string, string>();
        
        switch (intentType)
        {
            case "inventory_query":
                var skuMatch = System.Text.RegularExpressions.Regex.Match(message, @"[A-Za-z0-9\-_]+");
                if (skuMatch.Success) entities["sku"] = skuMatch.Value;
                break;
            case "order_query":
                var orderMatch = System.Text.RegularExpressions.Regex.Match(message, @"[A-Za-z0-9\-_]{6,}");
                if (orderMatch.Success) entities["order_code"] = orderMatch.Value;
                break;
        }
        
        return entities;
    }

    /// <summary>
    /// 计算相关性分数
    /// </summary>
    private float CalculateRelevanceScore(Admin.NET.Application.Entity.KnowledgeBase knowledge, string query, UserIntent intent)
    {
        float score = 0;
        
        // 标题匹配
        if (knowledge.Title.Contains(query)) score += 0.4f;
        
        // 内容匹配
        if (knowledge.Content.Contains(query)) score += 0.3f;
        
        // 关键词匹配
        if (knowledge.Keywords.Contains(query)) score += 0.2f;
        
        // 意图匹配
        if (knowledge.Category == intent.Type) score += 0.1f;
        
        return score;
    }

    /// <summary>
    /// 获取对话历史（恢复数据库功能）
    /// </summary>
    private async Task<List<CustomerServiceMessage>> GetConversationHistory(string conversationId)
    {
        try
        {
            var history = await _messageRepo.GetListAsync(m => m.ConversationId == conversationId);
            Console.WriteLine($"从数据库获取到 {history.Count} 条对话历史");
            return history;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"获取对话历史失败: {ex.Message}");
            return new List<CustomerServiceMessage>();
        }
    }

    /// <summary>
    /// 判断是否需要创建工单
    /// </summary>
    private bool ShouldCreateWorkOrder(UserIntent intent, string response)
    {
        return intent.Type == "error_report" || 
               response.Contains("工单") || 
               response.Contains("技术支持");
    }

    /// <summary>
    /// 判断是否需要转接人工
    /// </summary>
    private bool ShouldTransferToHuman(UserIntent intent, string response)
    {
        return intent.Type == "work_order" || 
               response.Contains("转人工") || 
               response.Contains("人工客服");
    }

    /// <summary>
    /// 创建工单
    /// </summary>
    [DisplayName("创建工单")]
    public async Task<WorkOrder> CreateWorkOrder(WorkOrder input)
    {
        input.OrderCode = $"WO{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(1000, 9999)}";
        input.Status = "pending";
        input.CreateTime = DateTime.Now;
        
        await _workOrderRepo.InsertAsync(input);
        return input;
    }

    /// <summary>
    /// 转接人工客服
    /// </summary>
    [DisplayName("转接人工客服")]
    public async Task TransferToHuman(TransferToHumanRequest input)
    {
        var workOrder = new WorkOrder
        {
            OrderCode = $"TR{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(1000, 9999)}",
            UserId = input.UserId,
            UserName = input.UserName,
            Title = "RAG转接人工客服",
            Description = "用户通过RAG智能客服转接至人工客服",
            Priority = "medium",
            Status = "pending",
            Category = "other",
            CreateTime = DateTime.Now,
            ConversationHistory = input.ConversationHistory?.ToJson()
        };
        
        await _workOrderRepo.InsertAsync(workOrder);
    }
}

// 用户意图模型
public class UserIntent
{
    public string Type { get; set; }
    public float Confidence { get; set; }
    public Dictionary<string, string> Entities { get; set; } = new();
}

// 请求和响应模型
public class CustomerServiceRequest
{
    public string Message { get; set; }
    public string ConversationId { get; set; }
    public long UserId { get; set; }
    public string UserName { get; set; }
}

public class CustomerServiceResponse
{
    public string Message { get; set; }
    public string MessageType { get; set; }
    public List<CustomerServiceAction> Actions { get; set; }
    public bool WorkOrderCreated { get; set; }
    public bool TransferToHuman { get; set; }
    public string ConversationId { get; set; }
}

public class CustomerServiceAction
{
    public string Type { get; set; }
    public object Data { get; set; }
}

public class TransferToHumanRequest
{
    public string ConversationId { get; set; }
    public List<CustomerServiceMessage> ConversationHistory { get; set; }
    public long UserId { get; set; }
    public string UserName { get; set; }
}

// RAGFlow API响应模型
public class RAGFlowResponse
{
    [JsonPropertyName("id")]
    public string Id { get; set; }
    
    [JsonPropertyName("object")]
    public string Object { get; set; }
    
    [JsonPropertyName("created")]
    public long Created { get; set; }
    
    [JsonPropertyName("model")]
    public string Model { get; set; }
    
    [JsonPropertyName("choices")]
    public RAGFlowChoice[] Choices { get; set; }
    
    [JsonPropertyName("usage")]
    public RAGFlowUsage Usage { get; set; }
}

public class RAGFlowChoice
{
    [JsonPropertyName("index")]
    public int Index { get; set; }
    
    [JsonPropertyName("message")]
    public RAGFlowMessage Message { get; set; }
    
    [JsonPropertyName("finish_reason")]
    public string FinishReason { get; set; }
}

public class RAGFlowMessage
{
    [JsonPropertyName("role")]
    public string Role { get; set; }
    
    [JsonPropertyName("content")]
    public string Content { get; set; }
}

public class RAGFlowUsage
{
    [JsonPropertyName("prompt_tokens")]
    public int PromptTokens { get; set; }
    
    [JsonPropertyName("completion_tokens")]
    public int CompletionTokens { get; set; }
    
    [JsonPropertyName("total_tokens")]
    public int TotalTokens { get; set; }
}

// RAGflow聊天会话相关模型
public class RAGFlowChatsResponse
{
    public int Code { get; set; }
    public RAGFlowChat[] Data { get; set; }
}

public class RAGFlowCreateChatResponse
{
    public int Code { get; set; }
    public RAGFlowChat Data { get; set; }
}

public class RAGFlowChat
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string CreateDate { get; set; }
    public long CreateTime { get; set; }
}

// RAGflow流式响应模型
public class RAGFlowStreamChunk
{
    public string Id { get; set; }
    public string Object { get; set; }
    public long Created { get; set; }
    public string Model { get; set; }
    public RAGFlowStreamChoice[] Choices { get; set; }
    public RAGFlowUsage Usage { get; set; }
}

public class RAGFlowStreamChoice
{
    public int Index { get; set; }
    public RAGFlowStreamDelta Delta { get; set; }
    public string FinishReason { get; set; }
}

public class RAGFlowStreamDelta
{
    public string Content { get; set; }
    public string Role { get; set; }
}

// Embedding API 响应（精简版）
public class EmbeddingResponseLike
{
    public EmbeddingDataLike[] Data { get; set; }
}

public class EmbeddingDataLike
{
    public float[] Embedding { get; set; }
}

// Qdrant 搜索响应（精简版）
public class QdrantSearchResponseLike
{
    public QdrantSearchResultLike[] Result { get; set; }
}

public class QdrantSearchResultLike
{
    public long Id { get; set; }
    public float Score { get; set; }
    public object Payload { get; set; }
}

// 个人记忆载荷与项目
public class PersonalMemoryPayload
{
    public long user_id { get; set; }
    public string conversation_id { get; set; }
    public string role { get; set; }
    public string content { get; set; }
    public string created_at { get; set; }
}

public class PersonalMemoryItem
{
    public string Content { get; set; }
    public string Role { get; set; }
    public string ConversationId { get; set; }
    public float Score { get; set; }
}

// 解析辅助
public partial class CustomerServiceService
{
    private bool TryExtractPersonalPayload(object payloadObj, out PersonalMemoryPayload payload)
    {
        payload = null;
        try
        {
            // 处理 JsonElement（来自 JsonDocument 解析）
            if (payloadObj is JsonElement je)
            {
                // 检查 JsonElement 的实际结构
                if (je.ValueKind != JsonValueKind.Object)
                {
                    return false;
                }
                
                // 直接从 JsonElement 读取字段
                var content = je.TryGetProperty("content", out var c) ? c.GetString() : null;
                var role = je.TryGetProperty("role", out var r) ? r.GetString() : null;
                var conversationId = je.TryGetProperty("conversation_id", out var conv) ? conv.GetString() : null;
                var userId = je.TryGetProperty("user_id", out var u) && u.ValueKind == JsonValueKind.Number ? u.GetInt64() : 0;
                var createdAt = je.TryGetProperty("created_at", out var t) ? t.GetString() : null;
                
                if (!string.IsNullOrEmpty(content))
                {
                    payload = new PersonalMemoryPayload
                    {
                        content = content,
                        role = role,
                        conversation_id = conversationId,
                        user_id = userId,
                        created_at = createdAt
                    };
                    return true;
                }
            }
            // 处理 Dictionary<string, object>（来自序列化后的数据）
            else if (payloadObj is Dictionary<string, object> dict)
            {
                var content = dict.TryGetValue("content", out var c) && c != null ? c.ToString() : null;
                var role = dict.TryGetValue("role", out var r) && r != null ? r.ToString() : null;
                var conversationId = dict.TryGetValue("conversation_id", out var conv) && conv != null ? conv.ToString() : null;
                var userId = 0L;
                if (dict.TryGetValue("user_id", out var u) && u != null)
                {
                    if (u is long l) userId = l;
                    else if (u is int i) userId = i;
                    else if (long.TryParse(u.ToString(), out var parsed)) userId = parsed;
                }
                var createdAt = dict.TryGetValue("created_at", out var t) && t != null ? t.ToString() : null;
                
                if (!string.IsNullOrEmpty(content))
                {
                    payload = new PersonalMemoryPayload
                    {
                        content = content,
                        role = role,
                        conversation_id = conversationId,
                        user_id = userId,
                        created_at = createdAt
                    };
                    return true;
                }
            }
            else if (payloadObj is string s && !string.IsNullOrEmpty(s))
            {
                var p = JsonSerializer.Deserialize<PersonalMemoryPayload>(s);
                if (p != null && !string.IsNullOrEmpty(p.content))
                {
                    payload = p;
                    return true;
                }
            }
            else
            {
                // 其他类型，尝试序列化再解析
                var json = JsonSerializer.Serialize(payloadObj);
                var p = JsonSerializer.Deserialize<PersonalMemoryPayload>(json);
                if (p != null && !string.IsNullOrEmpty(p.content))
                {
                    payload = p;
                    return true;
                }
            }
        }
        catch { }
        return false;
    }

    /// <summary>
    /// 获取个人记忆列表（分页）
    /// </summary>
    [DisplayName("获取个人记忆列表")]
    [ApiDescriptionSettings(Name = "GetPersonalMemoryPage"), HttpPost]
    public async Task<PersonalMemoryPageResult> GetPersonalMemoryPage([FromBody] PersonalMemoryPageInput input)
    {
        var result = new PersonalMemoryPageResult
        {
            Total = 0,
            Items = new List<PersonalMemoryOutput>()
        };

        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collection = _configuration["RAGSettings:QdrantMemoryCollection"] ?? "wms_personal_memory";
            
            Console.WriteLine($"[PersonalMemory] 开始查询，UserId={input.UserId}, Keyword={input.Keyword}, Page={input.Page}, PageSize={input.PageSize}");
            
            using var http = new HttpClient();
            http.Timeout = TimeSpan.FromSeconds(30);
            
            // 构建过滤条件
            var filterConditions = new List<object>();
            if (input.UserId.HasValue && input.UserId.Value > 0)
            {
                filterConditions.Add(new { key = "user_id", match = new { value = input.UserId.Value } });
            }

            var body = new
            {
                limit = 1000, // 先获取足够多的数据用于过滤和分页
                with_payload = true,
                filter = filterConditions.Count > 0 ? new { must = filterConditions.ToArray() } : (object)null
            };

            var json = JsonSerializer.Serialize(body);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            
            Console.WriteLine($"[PersonalMemory] 调用Qdrant API: {qdrantUrl}/collections/{collection}/points/scroll");
            
            var resp = await http.PostAsync($"{qdrantUrl}/collections/{collection}/points/scroll", content);
            
            if (!resp.IsSuccessStatusCode)
            {
                var errorContent = await resp.Content.ReadAsStringAsync();
                Console.WriteLine($"[PersonalMemory] Qdrant API调用失败: {resp.StatusCode}, {errorContent}");
                throw new Exception($"Qdrant API调用失败: {resp.StatusCode}");
            }
            
            var responseContent = await resp.Content.ReadAsStringAsync();
            Console.WriteLine($"[PersonalMemory] Qdrant响应长度: {responseContent.Length}");
            
            // 解析 Qdrant 响应（尝试多种格式）
            QdrantScrollPointLike[] points = null;
            
            try
            {
                // 方法1: 使用 JsonDocument 灵活解析
                using var doc = JsonDocument.Parse(responseContent);
                var root = doc.RootElement;
                
                // 检查是否有 result 字段
                if (root.TryGetProperty("result", out var resultElement))
                {
                    // 检查 result 中是否有 points 字段
                    if (resultElement.TryGetProperty("points", out var pointsElement) && pointsElement.ValueKind == JsonValueKind.Array)
                    {
                        var pointList = new List<QdrantScrollPointLike>();
                        foreach (var pointElem in pointsElement.EnumerateArray())
                        {
                            var point = new QdrantScrollPointLike();
                            if (pointElem.TryGetProperty("id", out var idElem))
                            {
                                point.Id = idElem.GetInt64();
                            }
                            if (pointElem.TryGetProperty("payload", out var payloadElem))
                            {
                                // 直接提取 payload 数据，避免 JsonDocument 释放后 JsonElement 失效
                                // 将 JsonElement 序列化为字符串，再反序列化为字典，确保数据可用
                                var payloadJson = payloadElem.GetRawText();
                                point.Payload = JsonSerializer.Deserialize<Dictionary<string, object>>(payloadJson);
                            }
                            pointList.Add(point);
                        }
                        points = pointList.ToArray();
                        Console.WriteLine($"[PersonalMemory] 使用JsonDocument解析成功，找到 {points.Length} 个points");
                    }
                }
                
                // 如果方法1失败，尝试方法2：标准反序列化
                if (points == null)
                {
                    var parsed = JsonSerializer.Deserialize<QdrantScrollResponseLike>(responseContent);
                    if (parsed?.Result?.Points != null)
                    {
                        points = parsed.Result.Points;
                        Console.WriteLine($"[PersonalMemory] 使用标准格式解析成功，找到 {points.Length} 个points");
                    }
                }
            }
            catch (Exception parseEx)
            {
                Console.WriteLine($"[PersonalMemory] 响应解析异常: {parseEx.Message}");
                Console.WriteLine($"[PersonalMemory] 响应内容前1000字符: {Truncate(responseContent, 1000)}");
            }
            
            if (points != null && points.Length > 0)
            {
                Console.WriteLine($"[PersonalMemory] 从Qdrant获取到 {points.Length} 个points");
                
                var allMemories = new List<PersonalMemoryOutput>();
                
                foreach (var p in points)
                {
                    if (TryExtractPersonalPayload(p.Payload, out var payload))
                    {
                        // 关键词过滤
                        if (!string.IsNullOrEmpty(input.Keyword))
                        {
                            var keywordLower = input.Keyword.ToLower();
                            if (!payload.content.ToLower().Contains(keywordLower))
                            {
                                continue;
                            }
                        }

                        allMemories.Add(new PersonalMemoryOutput
                        {
                            Id = p.Id,
                            UserId = payload.user_id,
                            ConversationId = payload.conversation_id ?? "",
                            Role = payload.role ?? "",
                            Content = payload.content ?? "",
                            CreatedAt = payload.created_at ?? ""
                        });
                    }
                    else
                    {
                        // 输出 payload 的详细信息用于调试
                        try
                        {
                            var payloadStr = p.Payload?.ToString() ?? "null";
                            var preview = payloadStr.Length > 200 ? payloadStr.Substring(0, 200) : payloadStr;
                            Console.WriteLine($"[PersonalMemory] 警告：无法解析point {p.Id} 的payload，预览: {preview}");
                            
                            // 如果 payload 是 JsonElement，尝试直接读取
                            if (p.Payload is System.Text.Json.JsonElement je)
                            {
                                Console.WriteLine($"[PersonalMemory] Payload类型: JsonElement, ValueKind: {je.ValueKind}");
                                if (je.ValueKind == System.Text.Json.JsonValueKind.Object)
                                {
                                    var keys = new List<string>();
                                    foreach (var prop in je.EnumerateObject())
                                    {
                                        keys.Add(prop.Name);
                                    }
                                    Console.WriteLine($"[PersonalMemory] Payload字段: {string.Join(", ", keys)}");
                                }
                            }
                        }
                        catch (Exception debugEx)
                        {
                            Console.WriteLine($"[PersonalMemory] 调试信息输出失败: {debugEx.Message}");
                        }
                    }
                }

                Console.WriteLine($"[PersonalMemory] 解析后得到 {allMemories.Count} 条有效记忆（过滤后）");

                // 按创建时间倒序排序
                allMemories = allMemories.OrderByDescending(m => m.CreatedAt).ToList();

                result.Total = allMemories.Count;
                result.Items = allMemories.Skip((input.Page - 1) * input.PageSize).Take(input.PageSize).ToList();
                
                Console.WriteLine($"[PersonalMemory] 返回结果: Total={result.Total}, Items.Count={result.Items.Count}");
            }
            else
            {
                Console.WriteLine("[PersonalMemory] parsed.Result.Points 为 null，可能Qdrant集合为空或响应格式不正确");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"[PersonalMemory] 获取个人记忆列表失败: {ex.Message}");
            Console.WriteLine($"[PersonalMemory] 异常堆栈: {ex}");
            // 不抛出异常，返回空结果，避免前端显示错误
            // throw;
        }

        return result;
    }

    /// <summary>
    /// 删除个人记忆
    /// </summary>
    [DisplayName("删除个人记忆")]
    [ApiDescriptionSettings(Name = "DeletePersonalMemory"), HttpPost]
    public async Task DeletePersonalMemory([FromBody] BaseIdInput input)
    {
        if (input?.Id == null || input.Id <= 0)
        {
            throw new ArgumentException("无效的记忆ID");
        }

        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collection = _configuration["RAGSettings:QdrantMemoryCollection"] ?? "wms_personal_memory";
            
            using var http = new HttpClient();
            
            var body = new
            {
                points = new[] { input.Id }
            };

            var json = JsonSerializer.Serialize(body);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            var resp = await http.PostAsync($"{qdrantUrl}/collections/{collection}/points/delete", content);
            resp.EnsureSuccessStatusCode();

            Console.WriteLine($"[Memory] 删除个人记忆成功: ID={input.Id}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"删除个人记忆失败: {ex.Message}");
            throw;
        }
    }

    /// <summary>
    /// 批量删除个人记忆
    /// </summary>
    [DisplayName("批量删除个人记忆")]
    [ApiDescriptionSettings(Name = "BatchDeletePersonalMemory"), HttpPost]
    public async Task BatchDeletePersonalMemory([FromBody] List<long> ids)
    {
        if (ids == null || ids.Count == 0)
        {
            throw new ArgumentException("记忆ID列表不能为空");
        }

        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collection = _configuration["RAGSettings:QdrantMemoryCollection"] ?? "wms_personal_memory";
            
            using var http = new HttpClient();
            
            var body = new
            {
                points = ids.ToArray()
            };

            var json = JsonSerializer.Serialize(body);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            var resp = await http.PostAsync($"{qdrantUrl}/collections/{collection}/points/delete", content);
            resp.EnsureSuccessStatusCode();

            Console.WriteLine($"[Memory] 批量删除个人记忆成功: 数量={ids.Count}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"批量删除个人记忆失败: {ex.Message}");
            throw;
        }
    }

    /// <summary>
    /// 获取对话历史列表（分页）
    /// </summary>
    [DisplayName("获取对话历史列表")]
    [ApiDescriptionSettings(Name = "GetConversationHistoryPage"), HttpPost]
    public async Task<ConversationHistoryPageResult> GetConversationHistoryPage([FromBody] ConversationHistoryPageInput input)
    {
        var result = new ConversationHistoryPageResult
        {
            Total = 0,
            Items = new List<ConversationHistoryOutput>()
        };

        try
        {
            var query = _messageRepo.AsQueryable();
            
            // 用户ID过滤
            if (input.UserId.HasValue && input.UserId.Value > 0)
            {
                query = query.Where(m => m.UserId == input.UserId.Value);
            }
            
            // 对话ID过滤
            if (!string.IsNullOrEmpty(input.ConversationId))
            {
                query = query.Where(m => m.ConversationId == input.ConversationId);
            }
            
            // 关键词搜索（在消息内容中）
            if (!string.IsNullOrEmpty(input.Keyword))
            {
                query = query.Where(m => m.Message.Contains(input.Keyword));
            }
            
            // 获取总数
            result.Total = await query.CountAsync();
            
            // 分页查询
            var messages = await query
                .OrderByDescending(m => m.Timestamp)
                .ToPageListAsync(input.Page, input.PageSize);
            
            result.Items = messages.Select(m => new ConversationHistoryOutput
            {
                Id = m.Id,
                UserId = m.UserId,
                UserName = m.UserName,
                Message = m.Message,
                MessageType = m.MessageType,
                Timestamp = m.Timestamp,
                IsFromUser = m.IsFromUser,
                ConversationId = m.ConversationId,
                Actions = m.Actions
            }).ToList();
            
            Console.WriteLine($"[ConversationHistory] 查询成功: Total={result.Total}, Items.Count={result.Items.Count}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"[ConversationHistory] 获取对话历史列表失败: {ex.Message}");
            throw;
        }

        return result;
    }

    /// <summary>
    /// 删除对话历史（真删除）
    /// </summary>
    [DisplayName("删除对话历史")]
    [ApiDescriptionSettings(Name = "DeleteConversationHistory"), HttpPost]
    public async Task DeleteConversationHistory([FromBody] BaseIdInput input)
    {
        if (input?.Id == null || input.Id <= 0)
        {
            throw new ArgumentException("无效的记录ID");
        }

        try
        {
            // 真删除：使用 AsDeleteable().Where().ExecuteCommandAsync()
            var count = await _messageRepo.AsDeleteable()
                .Where(m => m.Id == input.Id)
                .ExecuteCommandAsync();
            
            if (count > 0)
            {
                Console.WriteLine($"[ConversationHistory] 删除对话历史成功: ID={input.Id}");
            }
            else
            {
                throw new ArgumentException("未找到要删除的记录");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"删除对话历史失败: {ex.Message}");
            throw;
        }
    }

    /// <summary>
    /// 批量删除对话历史（真删除）
    /// </summary>
    [DisplayName("批量删除对话历史")]
    [ApiDescriptionSettings(Name = "BatchDeleteConversationHistory"), HttpPost]
    public async Task BatchDeleteConversationHistory([FromBody] List<long> ids)
    {
        if (ids == null || ids.Count == 0)
        {
            throw new ArgumentException("记录ID列表不能为空");
        }

        try
        {
            // 真删除：批量删除
            var count = await _messageRepo.AsDeleteable()
                .Where(m => ids.Contains(m.Id))
                .ExecuteCommandAsync();
            
            Console.WriteLine($"[ConversationHistory] 批量删除对话历史成功: 删除数量={count}, 请求数量={ids.Count}");
            
            if (count == 0)
            {
                throw new ArgumentException("未找到要删除的记录");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"批量删除对话历史失败: {ex.Message}");
            throw;
        }
    }

    /// <summary>
    /// 清空所有个人记忆（Qdrant向量数据库）
    /// </summary>
    [DisplayName("清空所有个人记忆")]
    [ApiDescriptionSettings(Name = "ClearAllPersonalMemory"), HttpPost]
    public async Task ClearAllPersonalMemory()
    {
        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collection = _configuration["RAGSettings:QdrantMemoryCollection"] ?? "wms_personal_memory";
            
            using var http = new HttpClient();
            
            // 方法1: 删除集合并重新创建（更彻底）
            try
            {
                // 删除集合
                var deleteResp = await http.DeleteAsync($"{qdrantUrl}/collections/{collection}");
                if (deleteResp.IsSuccessStatusCode || deleteResp.StatusCode == System.Net.HttpStatusCode.NotFound)
                {
                    Console.WriteLine($"[Memory] 删除集合成功: {collection}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[Memory] 删除集合时出错（可能集合不存在）: {ex.Message}");
            }
            
            // 重新创建集合
            await EnsureQdrantCollectionAsync(collection);
            
            Console.WriteLine($"[Memory] 清空所有个人记忆成功: {collection}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"清空所有个人记忆失败: {ex.Message}");
            throw;
        }
    }

    /// <summary>
    /// 清空所有对话历史（MySQL数据库）
    /// </summary>
    [DisplayName("清空所有对话历史")]
    [ApiDescriptionSettings(Name = "ClearAllConversationHistory"), HttpPost]
    public async Task<int> ClearAllConversationHistory()
    {
        try
        {
            // 真删除：删除所有记录
            var count = await _messageRepo.AsDeleteable()
                .ExecuteCommandAsync();
            
            Console.WriteLine($"[ConversationHistory] 清空所有对话历史成功: 删除数量={count}");
            
            return count;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"清空所有对话历史失败: {ex.Message}");
            throw;
        }
    }
}

// Qdrant scroll 响应（精简）
public class QdrantScrollResponseLike
{
    public QdrantScrollResultLike Result { get; set; }
}

public class QdrantScrollResultLike
{
    public QdrantScrollPointLike[] Points { get; set; }
}

public class QdrantScrollPointLike
{
    public long Id { get; set; }
    public object Payload { get; set; }
}

// 个人记忆查询输入
public class PersonalMemoryPageInput
{
    public long? UserId { get; set; }
    public string? Keyword { get; set; }
    public int Page { get; set; } = 1;
    public int PageSize { get; set; } = 20;
}

// 个人记忆输出
public class PersonalMemoryOutput
{
    public long Id { get; set; }
    public long UserId { get; set; }
    public string ConversationId { get; set; }
    public string Role { get; set; }
    public string Content { get; set; }
    public string CreatedAt { get; set; }
}

// 个人记忆分页结果
public class PersonalMemoryPageResult
{
    public int Total { get; set; }
    public List<PersonalMemoryOutput> Items { get; set; }
}

// 对话历史查询输入
public class ConversationHistoryPageInput
{
    public long? UserId { get; set; }
    public string? ConversationId { get; set; }
    public string? Keyword { get; set; }
    public int Page { get; set; } = 1;
    public int PageSize { get; set; } = 20;
}

// 对话历史输出
public class ConversationHistoryOutput
{
    public long Id { get; set; }
    public long UserId { get; set; }
    public string UserName { get; set; }
    public string Message { get; set; }
    public string MessageType { get; set; }
    public DateTime Timestamp { get; set; }
    public bool IsFromUser { get; set; }
    public string ConversationId { get; set; }
    public string? Actions { get; set; }
}

// 对话历史分页结果
public class ConversationHistoryPageResult
{
    public int Total { get; set; }
    public List<ConversationHistoryOutput> Items { get; set; }
}

